home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / disk utilities / backup / backup_restore / backup_src_v3.20.lha / Backup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-06  |  62.2 KB  |  2,836 lines

  1. // Backup.c
  2. // 06 Dec 1996 11:23:22
  3.  
  4. #ifndef    BACKUP_INCLUDE
  5. #include "IncludeAll.c"
  6. #endif
  7. #include "Backup.h"
  8. #include "cdio.h"
  9. #include "FileSelect.h"
  10. #include "ByteCount.h"
  11. #include "Backup_proto.h"
  12. #include "BackupStrings.h"
  13.  
  14. // #define    d(x)    x
  15. #define    d(x)        ;
  16.  
  17. #define    DFLT_INCLUDE    "*"        // default Include Pattern
  18. #define    DFLT_EXCLUDE    ""        // default Exclude Pattern
  19.  
  20. #define    ULINE    12            // Nr. d. untersten Zeile im Namensfenster
  21.  
  22.  
  23. static long gettime(void);
  24. static short GetDrive(const char *str, short unit);
  25. static short FindDrive(const char *Name);
  26. static void CheckForCmdFile(const char *name, BPTR DirLock, char *dirname);
  27. static int  GetParms(int argc, const char **argv);
  28. static void cleanup(void);
  29. static void OpenAll(void);
  30. static void CleanupPasswordFont(void);
  31. static void DisplayNewDir(const struct DirEntry *aktdir);
  32. static ULONG __saveds __asm PreviewHookDisplay(register __a0 struct Hook *theHook,
  33.         register __a1 object,
  34.         register __a2 struct BCInfo *BCount);
  35. static void action(void);
  36. static void TestCompress(struct NameField *file);
  37. static unsigned long GetNewFile(struct Buffer *aktbuff, BOOL *FileFound);
  38. static BOOL isReadDiskFull(unsigned long ZusatzPlatz);
  39. static short lesen(void);
  40. static void initDisk(void);
  41. static void InitDiskUnit(short Unit, short DiskNo, BOOL FirstDisk);
  42. static void NewReadDisk(struct FileInfoBlock *fib);
  43. static long inhibit(BOOL onoff, struct DiskFlags *Dsk);
  44. static short CheckVolumes(const struct BackupOptions *Opt, short unit);
  45. static short CmpVolumeName(char *DirName, char *VolName);
  46. static void CheckDriveFormat(void);
  47.  
  48.  
  49. extern struct IntuitionBase *IntuitionBase;
  50. extern struct DosLibrary *DOSBase;
  51.  
  52. extern struct WBStartup *WBenchMsg;
  53.  
  54.  
  55. #ifdef    TAPEDEBUG
  56. // aus Backup_Tape.c
  57. short TapeDebugLevel;
  58. #endif
  59.  
  60. // aus Backup_Window.c
  61. extern struct TextAttr PWDFONT, DefaultFAttr;
  62. extern struct Screen *WBScreen;
  63. extern short WindowColumns;        // lichte Weite des Window in Chars
  64. extern unsigned long DiskChangeMaske;
  65.  
  66.  
  67. // aus Revision.c
  68. extern short Version;            // aktuelle Versionsnummer
  69.  
  70. // aus NextFile.c
  71. extern BOOL NextFileAbort;        // Abbruch-Flag für NextFile
  72.  
  73. // aus CmdFile.c
  74. extern FILE *aktCmdFile;        // fp für Kommandofile
  75. extern char __far CmdFileName[];    // Name des Kommandofile
  76.  
  77. // aus ProtFile.c
  78. extern FILE *ProtFileHandle;        // File Handle für Protokoll-File
  79.  
  80. // aus ScaledImageClass.c
  81. extern Class *ScaledImageClass;        // Image Class für skalierte Images
  82.  
  83.  
  84. struct Task *BackupTask;
  85.  
  86. static struct Window *prWindowPtr;    // original-Inhalt von Process->pr_WindowPtr
  87.  
  88. struct Window *aktWindow;
  89. struct TextFont *myFont = NULL;
  90. struct TextFont *ScreenFont = NULL;
  91. struct TextFont PasswordFont;
  92.  
  93. struct MsgPort *AppPort = NULL;        // Msg Port für AppMessages
  94. static struct BInputHandler *AppInput = NULL;
  95.  
  96. short BuffCount = MAX_CYLBUFF;        // tatsächliche Anzahl Buffer
  97.  
  98. struct DiskFlags __far *Disks = NULL;
  99. unsigned short NDisk = 0;        // Anzahl Einträge in Disks[]
  100.  
  101. BOOL toTape = FALSE;            // Backup erfolgt auf Tape
  102.  
  103. static BOOL InteractiveBackup = FALSE;    // Parameter sind manuell eingestellt
  104.  
  105. short BuffersFull = 0;            // Anzahl gefüllter Buffer
  106.  
  107. BOOL AllFilesRead;            // Backup-Ende (lesen) erreicht
  108. BPTR aktReadFileHandle = NULL;        // fh für Lese-File
  109.  
  110. static short ErrorCount = 0l;        // Zähler für aufgetretene Fehler
  111.  
  112.  
  113. struct Buffer __far CylBuff[MAX_CYLBUFF];    // Schreib-/Lese-Buffer (für je einen Cylinder)
  114.  
  115. // globale Disk-Parameter
  116. struct BackupDevInfo globDrvDat;
  117.  
  118. struct Buffer *AktReadBuffer;
  119. unsigned short ReadBuffNr, WriteBuffNr, OldestWriteBuffNr=(unsigned short)(~0);
  120.  
  121. struct FileInfoBlock __aligned __far Root_fib;
  122. struct PartitionInfo Root_pInfo;
  123.  
  124. static char __far zeile[129];
  125.  
  126. static char LinkPath[FMSIZE];
  127. static char *LinkPathPtr;
  128.  
  129. char WBDiskNames[FMSIZE];        // Laufwerksnamen aus WB ToolTypes
  130.  
  131. short DiskUnit;                // aktuelles Laufwerk für Backup
  132.  
  133. static BPTR InitialCurrentDir = ~0;    // CurrentDir-Lock bei Programmstart
  134.  
  135. unsigned char disknr;            // laufende Nummer der Backup-Diskette
  136.  
  137. long readoffset;            // Offset innerhalb des aktuellen Lese-Buffers
  138.  
  139. struct SignalSemaphore NFSema;        // Lock für aktName und dir NameField-Verkettung
  140. struct NameField *aktName;        // aktuelles NameField
  141. static struct NfSplit aktNameInfo;
  142.  
  143. struct BackupOptions myOptions;        // Einstellungen für die aktuelle Sicherung
  144.  
  145. char *BackupStartDir = NULL;        // Startdirectory für Backup
  146.  
  147. char *AktPath;                // Text mit aktuellem Suchpfad (bei NextFile)
  148. char __far NormalizedAktPath[FMSIZE];    // AktPath normalisiert
  149.  
  150.  
  151. static unsigned long TotalFiles;    // Anzahl zu sichernde Files
  152. static unsigned long TotalBytes;    // Anzahl zu sichernde Bytes
  153.  
  154.  
  155. // fortlaufende Numerierung für mehrfache Sicherungen auf einem Medium
  156. // (mit Append,  ist == 0 bei normaler (Einzel-) Sicherung
  157. unsigned short CurrentSessionNr = 0;
  158.  
  159.  
  160. struct Disk ReadDisk;
  161. struct Disk WriteDisk;
  162.  
  163. static struct SignalSemaphore WriteDiskSema;
  164.  
  165.  
  166. struct NextFileInfo NFInfo =        // Datensatz für NextFile()
  167.     {
  168.     0L, 0, 0L, NULL, NULL,
  169.     { (struct MinNode *) &NFInfo.nfi_FirstDir.mlh_Tail,
  170.         NULL, (struct MinNode *) &NFInfo.nfi_FirstDir },
  171.     NULL, NULL };
  172.  
  173. // Variablen für Backup-Statistik
  174. unsigned long FilesProcessed;        // Anzahl Files
  175. unsigned long BytesProcessed;        // Anzahl Bytes
  176. char StartZeit[8];
  177.  
  178. // Declarations for CBACK
  179. extern BPTR __Backstdout;    // standard output when run in background
  180. long __BackGroundIO = 0;    // Flag to tell it we don't want to do I/O
  181. long __stack = MIN_STACK;    // Amount of stack space our task needs  
  182. char *__procname = "Backup";    // The name of the task to create        
  183. long __priority = 0;        // The priority to run us at             
  184.  
  185.  
  186. #undef min
  187. int min(int aa, int bb)
  188. {
  189.     return ( aa < bb ? aa : bb );
  190. }
  191.  
  192.  
  193. #undef max
  194. int max(int aa, int bb)
  195. {
  196.     return ( aa < bb ? bb : aa );
  197. }
  198.  
  199.  
  200. int sectotrack(int sektor)
  201. {
  202.     return (int) (sektor / (globDrvDat.NumHeads * globDrvDat.NumSecs));
  203. }
  204.  
  205.  
  206. // liefert nächsthöhere integere Zahl von a/b
  207. int ceildiv(int a, int b)
  208. {
  209.     int erg;
  210.  
  211.     erg = a / b;
  212.     if (a % b)
  213.         erg++;
  214.     return erg;
  215. }
  216.  
  217.  
  218. // (Fehler-)Meldung absetzen
  219. void PostError(BOOL Primary, enum MsgPriority Priority, const char *ErrText, ...)
  220. {
  221.     va_list args;
  222.  
  223.     ASSERT_VALID(ErrText);
  224.  
  225.     va_start(args, ErrText);
  226.  
  227.     if (Priority >= myOptions.bo_WarnLevel)
  228.         {
  229.         char zeile[129];
  230.  
  231.         vsprintf(zeile, ErrText, args);
  232.  
  233.         ErrorCount++;
  234.  
  235.         SignalUnIconifyMainWindow();
  236.  
  237.         if (Primary)
  238.             AddErrorText(zeile, NULL);
  239.         else
  240.             AddErrorText(NULL, zeile, NULL);
  241.         }
  242.  
  243.     va_end(args);
  244. }
  245.  
  246.  
  247. const char *ShortFileName(const char *RawName, short maxlen)
  248. {
  249.     static char NameSpace[FMSIZE];
  250.     const char *result;
  251.     short len, pos;
  252.  
  253.     ASSERT_VALID(RawName);
  254.  
  255.     len = strlen(RawName);
  256.     if (len > maxlen)
  257.         {
  258.         // zu lange Zeile wird als "Anfang...Ende" angezeigt
  259.         pos = (2 * maxlen) / 3 - 3;
  260.  
  261.         stccpy(NameSpace, RawName, min(pos, sizeof(NameSpace)));
  262.         strcat(NameSpace, "...");
  263.         strcat(NameSpace, RawName + len - maxlen + pos+3);
  264.  
  265.         result = NameSpace;
  266.         }
  267.     else
  268.         result = RawName;
  269.  
  270.     return result;
  271. }
  272.  
  273.  
  274. // liefert Zeit in hundertstel s
  275. static long gettime()
  276. {
  277.     static char clock[8];
  278.     long secs;
  279.  
  280.     getclk(clock);
  281.     secs = ((clock[4]*60)+clock[5])*60+clock[6];
  282.     return 100*secs + clock[7];
  283. }
  284.  
  285.  
  286. // liefert den nackten Filenamen aus "name"
  287. // ohne Path
  288. unsigned const char *NurName(const char *name)
  289. {
  290.     ASSERT_VALID(name);
  291.  
  292.     return FilePart((STRPTR) name);
  293. }
  294.  
  295.  
  296. int myatoi(const char **str, int n)
  297. {
  298.     int erg = 0;
  299.  
  300.     ASSERT_VALID(*str);
  301.  
  302.     *str = stpblk(*str);
  303.     while (n && **str && isdigit(**str))
  304.         {
  305.         erg = 10 * erg + (**str - '0');
  306.         (*str)++;
  307.         n--;
  308.         }
  309.     return erg;
  310. }
  311.  
  312.  
  313. // Tagesnummer (long, ab 1.1.1978) umwandeln in Tag,Monat,Jahr
  314. short UnpackDate(long Day, struct myDate *Date)
  315. {
  316.     char DateStr[6];
  317.  
  318.     ASSERT_VALID(Date);
  319.  
  320.     utunpk((Day+YEARDIFF)*3600l*24l, DateStr);
  321.     Date->Day = DateStr[2];
  322.     Date->Month = DateStr[1];
  323.     Date->Year = DateStr[0] + YEARZERO;
  324.  
  325.     return 0;
  326. }
  327.  
  328.  
  329. // Datum in Tagesnummer (long, ab 1.1.1978) umwandeln
  330. // liefert ~0 bei Fehler im Datum
  331. long PackDate(short Tag, short Monat, short Jahr)
  332. {
  333.     long tagnr;
  334.     short ok;
  335.     struct DateTime dt;
  336.     char DateStr[20];
  337.  
  338.     if (Jahr > 1900)
  339.         Jahr -= 1900;
  340.  
  341.     sprintf(DateStr, "%d-%d-%d", Monat, Tag, Jahr);
  342.     dt.dat_Format = FORMAT_USA;
  343.     dt.dat_Flags = 0;
  344.     dt.dat_StrDate = DateStr;
  345.     dt.dat_StrTime = NULL;
  346.  
  347.     ok = StrToDate(&dt);
  348.     tagnr = dt.dat_Stamp.ds_Days;
  349.  
  350.     return ok ? tagnr : ~0l;
  351. }
  352.  
  353.  
  354. char *ReadString(char *nach, const char *von, size_t maxlen)
  355. {
  356.     char FirstC;
  357.  
  358.     ASSERT_VALID(nach);
  359.     ASSERT_VALID(von);
  360.  
  361.     FirstC = *von;
  362.     if (FirstC == '"')
  363.         von++;
  364.  
  365.     while (maxlen && *von && ((FirstC == '"' && *von != '"') ||
  366.             (FirstC != '"' && !isspace(*von))))
  367.         {
  368.         *nach++ = *von++;
  369.         maxlen--;
  370.         }
  371.     *nach = '\0';
  372.  
  373.     if (*von && FirstC == '"')
  374.         von++;        // " am Schluß überlesen
  375.  
  376.     return von;
  377. }
  378.  
  379.  
  380. static short GetDrive(const char *str, short unit)
  381. {
  382.     short len, n;
  383.     char *DupStr;
  384.  
  385.     ASSERT_VALID(str);
  386.     assert(unit == NO_DRIVE || (unit >= 0 && unit < NDisk));
  387.  
  388.     // das ':' am Ende des Device-Namens muß für FindDrive() entfernt werden.
  389.     DupStr = strdup(str);
  390.     if (NULL == DupStr)
  391.         {
  392.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DupStr", strlen(str));
  393.         myabort(20);
  394.         }
  395.     len = strlen(DupStr);
  396.     if (DupStr[len-1] == ':')
  397.         DupStr[len-1] = '\0';
  398.  
  399.     n = FindDrive(DupStr);
  400.  
  401.     free(DupStr);
  402.  
  403.     if (n == NO_DRIVE)
  404.         {
  405.         alarm(GetString(MSG_NOT_A_VALID_DRIVE), str);
  406.         myabort(0);
  407.         }
  408.     if (n == unit)
  409.         {
  410.         alarm(GetString(MSG_ALREADY_INUSE), Disks[n].DOSName);
  411.         n = NO_DRIVE;
  412.         }
  413.  
  414.     return n;
  415. }
  416.  
  417.  
  418.  
  419. static short FindDrive(const char *Name)
  420. {
  421.     short n;
  422.     BOOL found;
  423.  
  424.     ASSERT_VALID(Name);
  425.  
  426.     for (n=0, found=FALSE; !found && n<NDisk; )
  427.         {
  428.         found = Disks[n].valid && stricmp(Disks[n].DOSName, Name) == 0;
  429.         if (!found)
  430.             n++;
  431.         }
  432.  
  433.     return (short) (found ? n : NO_DRIVE);
  434. }
  435.  
  436.  
  437.  
  438. static void CheckForCmdFile(const char *name, BPTR DirLock, char *dirname)
  439. {
  440.     char *path;
  441.     BPTR OldLock = NULL;
  442.  
  443.     ASSERT_VALID0(name);
  444.     ASSERT_VALID0(BADDR(DirLock));
  445.     ASSERT_VALID(dirname);
  446.  
  447.     if (name == NULL || *name == '\0')
  448.         return;
  449.  
  450.     strcpy(CmdFileName, name);
  451.  
  452.     if (DirLock)
  453.         OldLock = CurrentDir(DupLock(DirLock));
  454.  
  455.     if (!OpenCmdFile(CmdFileName))
  456.         {
  457.         if (OldLock)
  458.             UnLock(CurrentDir(OldLock));    // Current Dir restaurieren
  459.         myabort(1);
  460.         }
  461.  
  462.     if (aktCmdFile)
  463.         {
  464.         path = ReadCmdFile(&myOptions, 1);
  465.         if (path)
  466.             strcpy(dirname, path);
  467.         else
  468.             CloseCmdFile();
  469.         }
  470.  
  471.     if (OldLock)
  472.         UnLock(CurrentDir(OldLock));    // Current Dir restaurieren
  473. }
  474.  
  475.  
  476. void DefaultOptions(struct BackupOptions *Opts, BOOL NewFS)
  477. {
  478.     static char dirname[FMSIZE];
  479.     char zeit[8];
  480.  
  481.     ASSERT_VALID(Opts);
  482.  
  483.     if (NewFS)
  484.         {
  485.         Opts->bo_FSDirList = NULL;
  486.         Opts->bo_FSDirCount = 0L;
  487.  
  488.         Opts->bo_WhereSortDirs = DirFirst;    // default: Directories zuerst einsortieren
  489.  
  490.         Opts->bo_FSCompare = FSCompareName;    // default: sortieren nach Name
  491.         Opts->bo_HowToSort = SortName;
  492.         }
  493.  
  494.     Opts->bo_MainWindowPos.Left = 0;
  495.     Opts->bo_MainWindowPos.Top = 25;
  496.     Opts->bo_MainWindowPos.Width = BREITE;
  497.     Opts->bo_MainWindowPos.Height = HOEHE;
  498.  
  499.     Opts->bo_Append = FALSE;        // Default: kein Append
  500.     Opts->bo_IncludeSubDirs = TRUE;        // Default: mit Subdirectories
  501.     Opts->bo_UseArc = Ignore;        // Default: Archiv-Flag ist egal
  502.     Opts->bo_SetArc = Set;            // default: Archiv-Flag setzen
  503.     Opts->bo_ProtFile = PT_ASCII;        // default: mit Protokollfile
  504.     Opts->bo_Verify = FALSE;        // default: ohne Verify
  505.     Opts->bo_UseFirstDate = FALSE;        // default: nicht nach Datum prüfen
  506.     Opts->bo_UseLastDate = FALSE;        // default: nicht nach Datum prüfen
  507.     Opts->bo_Compress = COMPRESS_NONE;    // default: nicht komprimieren
  508.     Opts->bo_KeepProtFile = TRUE;        // default: Protokollfile nicht löschen
  509.     Opts->bo_SaveSoftLinks = FALSE;        // default: SoftLinks als Link sichern
  510.     Opts->bo_SaveHardLinks = TRUE;        // default: HardLinks als Inhalt sichern
  511.     Opts->bo_Preview = FALSE;        // default: kein Preview
  512.     Opts->bo_UseHardwareCompression = TRUE;    // default: Hardware-Kompression nutzen
  513.     Opts->bo_UseGrepPattern = TRUE;        // default: OS2.0 #? Wildcards nutzen
  514.     Opts->bo_Iconify = FALSE;        // default: nicht ikonifizieren
  515.     Opts->bo_WarnDosDisk = TRUE;        // default: Nachfragen bei DOS-Disk
  516.  
  517.     Opts->bo_WarnLevel = 0;            // default: alles anzeigen
  518.  
  519.     Opts->bo_AppIconPosX = NO_ICON_POSITION;
  520.     Opts->bo_AppIconPosY = NO_ICON_POSITION;
  521.  
  522.     Opts->bo_QFAPartitionSize = DEFAULT_QFA_PARTSIZE;    // Größe für die QFA-Partition in MB
  523.  
  524.     BackupStartDir = dirname;
  525.  
  526.     // Datumsgrenzen default vom 1.1.80 bis heute
  527.     Opts->bo_FirstDate = ReadDate(DateString(1, 1, 80));
  528.     getclk(zeit);
  529.     Opts->bo_LastDate = ReadDate(DateString(zeit[3], zeit[2], zeit[1]+80));
  530.  
  531.     getcwd(dirname, 128);        // Default Directory
  532.     if ( strchr(dirname, ':')==NULL && dirname[strlen(dirname)-1]!=':')
  533.         strcat(dirname, ":");
  534.  
  535.     strcpy(Opts->bo_AppIconName, "");
  536.  
  537.     strcpy(Opts->bo_CmdFileIcon, "");
  538.     strcpy(Opts->bo_DrivesWithoutGeometry, "");
  539.  
  540.     strcpy(Opts->bo_IncludeFile.RawName, DFLT_INCLUDE);
  541.     strcpy(Opts->bo_ExcludeFile.RawName, DFLT_EXCLUDE);
  542.  
  543.     strcpy(Opts->bo_ProtFileName, LOGDIR LOGNAME);
  544.     strcpy(Opts->bo_DiskSavePrefix, DEFAULT_DISKSAVE);
  545.     strcpy(Opts->bo_HelpPath, DEFAULT_HELPPATH);
  546.     strcpy(Opts->bo_ScriptPath, DEFAULT_SCRIPTPATH);
  547.     strcpy(Opts->bo_TapeDriveDataFileName, DEFAULT_TAPEDRIVEDATABASE);
  548.  
  549.     strcpy(Opts->bo_Language, "");            // default: System-Standardsprache
  550.     strcpy(Opts->bo_PubScreen, "");            // default: Default Screen
  551.     strcpy(Opts->bo_CurrentDir, "PROGDIR:");    // default: PROGDIR:
  552.  
  553.     // Defaultwerte für bo_ListFontName werden aus dem System Default Font übernommen!!
  554.     sprintf(Opts->bo_ListFontName, "%s/%d", DefaultFAttr.ta_Name, DefaultFAttr.ta_YSize);
  555.  
  556.     TranslateWildCards(Opts);
  557. }
  558.  
  559.  
  560. void SetupDrives(struct BackupOptions *Opt, const char *DriveNames)
  561. {
  562.     short n;
  563.  
  564.     ASSERT_VALID(DriveNames);
  565.  
  566.     Opt->bo_FirstUnit = Opt->bo_SecondUnit = NO_DRIVE;
  567.  
  568.     for (n=NDisk-1; n>=0; n--)
  569.         {
  570.         if (Disks[n].valid && MatchToolValue((STRPTR) DriveNames, Disks[n].DOSName))
  571.             {
  572.             if (Opt->bo_FirstUnit == NO_DRIVE)
  573.                 Opt->bo_FirstUnit = n;
  574.             else if (Opt->bo_SecondUnit == NO_DRIVE && n != Opt->bo_FirstUnit)
  575.                 Opt->bo_SecondUnit = n;
  576.             }
  577.         }
  578. }
  579.  
  580.  
  581. static int GetParms(int argc, const char *argv[])
  582. {
  583.     static char dirname[FMSIZE] = "";
  584.     short drvdef, i;
  585.  
  586.     ASSERT_VALID(argv);
  587.  
  588.     DefaultOptions(&myOptions, 1);
  589.  
  590.     // Wenn von Workbench gestartet, aus den Tool Types die default-
  591.     // Werte für die diversen Flags lesen
  592.     if (argc == 0)        // Start von Workbench
  593.         {
  594.         // WB Tool Types auswerten.
  595.         // vor getdisks() damit die Tape-Namen vorgegeben werden können.
  596.         struct WBArg CmdFile;
  597.  
  598.         WBDiskNames[0] = '\0';
  599.  
  600.         if (GetWBDefaults(&CmdFile, WBenchMsg, &myOptions))
  601.             CheckForCmdFile(CmdFile.wa_Name, CmdFile.wa_Lock, dirname);
  602.         }
  603.  
  604.     myOpenLocale(myOptions.bo_Language);
  605.     OpenBackupScreen(*myOptions.bo_PubScreen ? myOptions.bo_PubScreen : NULL);
  606.  
  607.     getdisks();            // Verfügbare Disk-Laufwerke suchen
  608.  
  609.     if (argc == 0)
  610.         {
  611.         // Laufwerke aus WB Tool Types übernehmen.
  612.         // MUSS nach getdisks() erfolgen!!!!!
  613.         SetupDrives(&myOptions, WBDiskNames);
  614.         }
  615.  
  616.     SetupNextFileInfo(&NFInfo, &myOptions, DisplayNewDir);
  617.  
  618.     // Default-Laufwerk(e) festlegen (die beiden höchsten verfügbaren
  619.     // Laufwerke DFx  werden für LW 1 und 2 verwendet)
  620.     if (myOptions.bo_FirstUnit == NO_DRIVE)
  621.         {
  622.         for (i=3-1; i>=0; i--)
  623.             {
  624.             int DiskNo;
  625.  
  626.             sprintf(zeile, "DF%d", i);
  627.             if ((DiskNo = FindDrive(zeile)) != NO_DRIVE)
  628.                 {
  629.                 if (myOptions.bo_FirstUnit == NO_DRIVE)
  630.                     {
  631.                     myOptions.bo_FirstUnit = DiskNo;
  632.                     myOptions.bo_SecondUnit = NO_DRIVE;
  633.                     }
  634.                 else if (myOptions.bo_SecondUnit == NO_DRIVE && DiskNo != myOptions.bo_FirstUnit)
  635.                     myOptions.bo_SecondUnit = DiskNo;
  636.                 }
  637.             }
  638.         }
  639.  
  640.     if (argc < 2)
  641.         {
  642.         if (aktCmdFile == NULL)
  643.             {
  644.             // ohne Kommandofile: Interaktives Backup!
  645.             InteractiveBackup = TRUE;
  646.  
  647.             if (!getargs(&myOptions))
  648.                 myabort(0);
  649.             }
  650.         }
  651.     else
  652.         {
  653.         if (strcmp(argv[1], "?") == 0)
  654.             {
  655.             CallHelp(0L, 0);
  656.             myabort(0);
  657.             }
  658.  
  659.         if (argv[1][0] == '@')
  660.             CheckForCmdFile(&argv[1][1], NULL, dirname);
  661.  
  662.         if (aktCmdFile == NULL)
  663.             {
  664.             stcgfp(dirname, argv[1]);        // Get file path
  665.             stcgfn(myOptions.bo_IncludeFile.RawName, argv[1]);    // Get file node
  666.             }
  667.         for (drvdef=0, i=2; i<argc; i++)
  668.             {
  669.             switch (argv[i][0])
  670.                 {
  671.             case '/':
  672.             case '-':        // Option
  673.                 processOption(&argv[i][1], "", &myOptions);
  674.                 break;
  675.             default:
  676.                 if (argv[i][strlen(argv[i])-1] == ':')
  677.                     {
  678.                     // Ziellaufwerk
  679.                     if (drvdef == 0)
  680.                         {
  681.                         myOptions.bo_FirstUnit = GetDrive(argv[i], NO_DRIVE);
  682.                         myOptions.bo_SecondUnit = NO_DRIVE;
  683.                         }
  684.                     else if (drvdef == 1)
  685.                         myOptions.bo_SecondUnit = GetDrive(argv[i], myOptions.bo_FirstUnit);
  686.                     else
  687.                         alarm(GetString(MSG_IGNORE_THIRD_DRIVE), argv[i]);
  688.                     drvdef++;
  689.                     }
  690.                 else
  691.                     {
  692.                     if (!CheckLineForToolType(argv[i], &myOptions))
  693.                         {
  694.                         // Schrott
  695.                         alarm(GetString(MSG_INVALID_PARAMETER), argv[i]);
  696.                         myabort(0);
  697.                         }
  698.                     }
  699.                 break;
  700.                 }
  701.             }
  702.         }
  703.  
  704.     if (*dirname)
  705.         NewDir(&NFInfo.nfi_FirstDir, dirname, 0);
  706.  
  707. #if 0
  708.     if (myOptions.bo_FirstUnit != NO_DRIVE)
  709.         {
  710.         printf(" First Unit %d: \"%s\" TapeReq=%08lx\n",
  711.             myOptions.bo_FirstUnit, 
  712.             Disks[myOptions.bo_FirstUnit].DOSName,
  713.             Disks[myOptions.bo_FirstUnit].TapeReq);
  714.         }
  715.     if (myOptions.bo_SecondUnit != NO_DRIVE)
  716.         {
  717.         printf("Second Unit %d: \"%s\" TapeReq=%08lx\n", 
  718.             myOptions.bo_SecondUnit, 
  719.             Disks[myOptions.bo_SecondUnit].DOSName,
  720.             Disks[myOptions.bo_SecondUnit].TapeReq);
  721.         }
  722. #endif
  723.  
  724.     return 1;
  725. }
  726.  
  727.  
  728. void myabort(int errcode)
  729. {
  730.     myOptions.bo_KeepProtFile = 0;
  731.  
  732.     exit(errcode);
  733. }
  734.  
  735.  
  736. static void cleanup(void)
  737. {
  738.     unsigned short i;
  739.  
  740.     StopWriter(TRUE);
  741.     ShutdownHelp();
  742.     CleanupError();
  743.     DeinitCompress();
  744.     CleanUpFS();
  745.     CleanupXGO();
  746.     CleanupXpk();
  747.     CleanupNextFileInfo(&NFInfo);
  748.     CleanupProtFile(FALSE);
  749.     CleanupTapeInfo();
  750.     CleanupAbout();
  751.     CleanupStat();
  752.     CleanupST();            // Cleanup für SetupTape
  753.     GlobalYesNoCleanup();
  754.  
  755.     CDClose();
  756.     CleanupMainWindow();
  757.     CleanupFileDisplay();
  758.  
  759.     if (myOptions.bo_ProtFile != PT_None && !myOptions.bo_KeepProtFile)
  760.         {
  761.         // ggf. temporäres Protokollfile löschen
  762.         DeleteFile(myOptions.bo_ProtFileName);
  763.         }
  764.  
  765.     if (AppPort)
  766.         {
  767.         RemBInputHandler(&AppInput);
  768.  
  769.         DeletePort(AppPort);
  770.         AppPort = NULL;
  771.         }
  772.     if (AktPath != NULL)
  773.         {
  774.         free(AktPath);
  775.         AktPath = NULL;
  776.         }
  777.     if (aktReadFileHandle)
  778.         {
  779.         Close(aktReadFileHandle);
  780.         aktReadFileHandle = NULL;
  781.         }
  782.     if (aktCmdFile)
  783.         CloseCmdFile();
  784.  
  785.     if (NDisk > 0 && myOptions.bo_FirstUnit != NO_DRIVE)
  786.         {
  787.         assert(myOptions.bo_FirstUnit >= 0 && myOptions.bo_FirstUnit < NDisk);
  788.         CleanUpDisk(&Disks[myOptions.bo_FirstUnit], TRUE);
  789.         myOptions.bo_FirstUnit = NO_DRIVE;
  790.         }
  791.     if (NDisk > 0 && myOptions.bo_SecondUnit != NO_DRIVE)
  792.         {
  793.         assert(myOptions.bo_SecondUnit >= 0 && myOptions.bo_SecondUnit < NDisk);
  794.         CleanUpDisk(&Disks[myOptions.bo_SecondUnit], TRUE);
  795.         myOptions.bo_SecondUnit = NO_DRIVE;
  796.         }
  797.  
  798.     ClosePartition(&Root_pInfo);        // evtl. offene Partition schließen
  799.  
  800.     for (i=0; i<BuffCount; i++)
  801.         {
  802.         if (CylBuff[i].dbp != NULL)
  803.             {
  804.             FreeVec(CylBuff[i].dbp);
  805.             CylBuff[i].dbp = NULL;
  806.             }
  807.         if (CylBuff[i].TapeReq)
  808.             {
  809.             FreeVec(CylBuff[i].TapeReq);
  810.             CylBuff[i].TapeReq = NULL;
  811.             }
  812.         }
  813.  
  814.     DeleteSaveInfo();
  815.  
  816.     CleanupRWDisk(&ReadDisk);
  817.     CleanupRWDisk(&WriteDisk);
  818.  
  819.     if (Disks)
  820.         {
  821.         free(Disks);
  822.         Disks = NULL;
  823.         }
  824.  
  825.     if (myFont)
  826.         {
  827.         CloseFont(myFont);
  828.         myFont = NULL;
  829.         }
  830.     if (ScreenFont)
  831.         {
  832.         CloseFont(ScreenFont);
  833.         ScreenFont = NULL;
  834.         }
  835.  
  836.     CleanupPasswordFont();
  837.  
  838.     if (InitialCurrentDir != ~0)
  839.         UnLock(CurrentDir(InitialCurrentDir));
  840.  
  841.     if (prWindowPtr)
  842.         {
  843.         ((struct Process*) BackupTask)->pr_WindowPtr = prWindowPtr;
  844.         prWindowPtr = NULL;
  845.         }
  846.  
  847.     if (ScaledImageClass)
  848.         {
  849.         freeScaledImageClass(ScaledImageClass);
  850.         ScaledImageClass = NULL;
  851.         }
  852.  
  853.     CloseLibraries();
  854. }
  855.  
  856.  
  857. // Angelegte Directory-Cylinderliste wieder auflösen
  858. void CleanupRWDisk(struct Disk *Dsk)
  859. {
  860.     struct DirBlock *aktblock;
  861.  
  862.     ASSERT_VALID(Dsk);
  863.  
  864.     while (Dsk->DirBuffers.mlh_Head != NULL && !IsListEmpty((struct List *) &Dsk->DirBuffers))
  865.         {
  866.         aktblock = (struct DirBlock *) RemHead((struct List *) &Dsk->DirBuffers);
  867.         if (aktblock->LostNF)
  868.             {
  869.             free(aktblock->LostNF);
  870.             aktblock->LostNF = NULL;
  871.             }
  872.         FreeVec(aktblock);
  873.         }
  874. }
  875.  
  876.  
  877. void CleanUpDisk(struct DiskFlags *Dsk, BOOL Release)
  878. {
  879.     ASSERT_VALID(Dsk);
  880.  
  881.     if (Dsk->DcI)
  882.         {
  883.         EndDiskChanger(Dsk->DcI);
  884.         Dsk->DcI = NULL;
  885.         }
  886.  
  887.     if (Dsk->inhibited)
  888.         inhibit(FALSE, Dsk);    // Laufwerk freigeben
  889.  
  890.     if (Release && Dsk->TapeReq)
  891.         {
  892.         FreeVec(Dsk->TapeReq);
  893.         Dsk->TapeReq = NULL;
  894.         }
  895. }
  896.  
  897.  
  898. static void OpenAll(void)
  899. {
  900.     atexit(cleanup);
  901.  
  902.     BackupTask = FindTask(NULL);
  903.  
  904.     prWindowPtr = ((struct Process*) BackupTask)->pr_WindowPtr;
  905.  
  906.     OpenLibraries();
  907.  
  908.     ScaledImageClass = initScaledImageClass();
  909.  
  910.     // System Default Font öffnen
  911.     myFont = OpenDiskFont(&DefaultFAttr);
  912.     if (NULL == myFont)
  913.         {
  914.         alarm(GetString(MSG_CANNOT_OPEN_FONT), DefaultFAttr.ta_Name);
  915.         myabort(10);
  916.         }
  917.  
  918.     if (WorkbenchBase)
  919.         {
  920.         if ((AppPort = CreatePort(NULL, 0)) == NULL)
  921.             {
  922.             alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "AppPort");
  923.             myabort(15);
  924.             }
  925.         else
  926.             {
  927.             AppInput = AddBInputHandler(1 << AppPort->mp_SigBit, HandleAppMsg);
  928.             }
  929.         }
  930.  
  931.     InitSemaphore(&NFSema);
  932.     InitXpk();
  933.  
  934.     InitTape();
  935. }
  936.  
  937.  
  938. static void CleanupPasswordFont(void)
  939. {
  940.     if (PasswordFont.tf_CharLoc)
  941.         {
  942.         RemFont(&PasswordFont);
  943.  
  944.         free(PasswordFont.tf_CharLoc);
  945.         PasswordFont.tf_CharLoc = NULL;
  946.         }
  947.  
  948.     if (PasswordFont.tf_Message.mn_ReplyPort)
  949.         {
  950.         DeleteMsgPort(PasswordFont.tf_Message.mn_ReplyPort);
  951.         PasswordFont.tf_Message.mn_ReplyPort = NULL;
  952.         }
  953. }
  954.  
  955.  
  956. // Initialisieren der IORequest's für die Cylinderbuffer
  957. short InitBufReq(void)
  958. {
  959.     unsigned short i;
  960.  
  961.     for (i=0; i<BuffCount; i++)
  962.         {
  963.         assert(DiskUnit >= 0 && DiskUnit < NDisk);
  964.  
  965.         if (CylBuff[i].BufIOReq.iotd_Req.io_Command != CMD_INVALID)
  966.             {
  967.             alarm(GetString(MSG_INITBUFREQ_BUFFER_NOT_FREE), i);
  968.             myabort(50);
  969.             }
  970.         CylBuff[i].BufIOReq = *Disks[DiskUnit].diskreq;
  971.         CylBuff[i].BufIOReq.iotd_Req.io_Command = CMD_INVALID;
  972.  
  973.         if (Disks[DiskUnit].TapeReq)
  974.             {
  975.             CylBuff[i].TapeReq = AllocVec(sizeof(struct TapeIO),
  976.                 globDrvDat.BufMemType);
  977.             if (CylBuff[i].TapeReq == NULL)
  978.                 {
  979.                 alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "TapeReq", sizeof(struct TapeIO));
  980.                 return TRUE;
  981.                 }
  982.             *CylBuff[i].TapeReq = *Disks[DiskUnit].TapeReq;
  983.             CylBuff[i].TapeReq->Req = &CylBuff[i].BufIOReq;
  984.             }
  985.         else if (myOptions.bo_Verify)
  986.             {
  987.             CylBuff[i].VerifyReq = *Disks[DiskUnit].diskreq;
  988.             CylBuff[i].VerifyReq.iotd_Req.io_Command = CMD_INVALID;
  989.             }
  990.         }
  991.  
  992.     return FALSE;
  993. }
  994.  
  995.  
  996. BOOL InitSearchPattern(struct BackupOptions *Opt)
  997. {
  998.     ASSERT_VALID(Opt);
  999.  
  1000.     if (Opt->bo_UseGrepPattern)
  1001.         {
  1002.         // Sicherstellen, daß alle Patterns bereit sind
  1003.  
  1004.         if (!Opt->bo_IncludeFile.isParsed)
  1005.             {
  1006.             if(ParsePatternNoCase(Opt->bo_IncludeFile.RawName,
  1007.                     Opt->bo_IncludeFile.ParsedPattern,
  1008.                     sizeof(Opt->bo_IncludeFile.ParsedPattern) ) == -1)
  1009.                 {
  1010.                 alarm(GetString(MSG_XLATEERROR_INCLUDE));
  1011.                 Opt->bo_IncludeFile.isParsed = 0;
  1012.  
  1013.                 return FALSE;
  1014.                 }
  1015.             else
  1016.                 {
  1017.                 Opt->bo_IncludeFile.isParsed = 1;
  1018.                 }
  1019.             }
  1020.         if (!Opt->bo_ExcludeFile.isParsed)
  1021.             {
  1022.             if(ParsePatternNoCase(Opt->bo_ExcludeFile.RawName,
  1023.                     Opt->bo_ExcludeFile.ParsedPattern,
  1024.                     sizeof(Opt->bo_ExcludeFile.ParsedPattern) ) == -1)
  1025.                 {
  1026.                 alarm(GetString(MSG_XLATEERROR_EXCLUDE));
  1027.                 Opt->bo_ExcludeFile.isParsed = 0;
  1028.  
  1029.                 return FALSE;
  1030.                 }
  1031.             else
  1032.                 {
  1033.                 Opt->bo_ExcludeFile.isParsed = 1;
  1034.                 }
  1035.             }
  1036.         }
  1037.     return TRUE;
  1038. }
  1039.  
  1040.  
  1041. // alle Zylinderpuffer anlegen
  1042. void AllocDiskBuffer(void)
  1043. {
  1044.     unsigned short i;
  1045.     unsigned long UsableMemory;
  1046.  
  1047.     if (CylBuff[0].dbp != NULL)
  1048.         return;            // ...war schon initialisiert
  1049.  
  1050.     BuffCount = MAX_CYLBUFF;
  1051.  
  1052.     UsableMemory = AvailMem(globDrvDat.BufMemType);
  1053.  
  1054.     UsableMemory = CreateSaveInfo(UsableMemory);
  1055.  
  1056.     // max. 1/2 des verfügbaren Speichers für Diskbuffer belegen !
  1057.     if (globDrvDat.CylSize * BuffCount > UsableMemory / 2)
  1058.         BuffCount = (UsableMemory / globDrvDat.CylSize) / 2;
  1059.  
  1060.     if (BuffCount < MIN_CYLBUFF)
  1061.         {
  1062.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DiskBuffer", MIN_CYLBUFF * globDrvDat.CylSize);
  1063.         myabort(10);
  1064.         }
  1065.  
  1066.     for (i=0; i<BuffCount; i++)
  1067.         {
  1068.         InitSemaphore(&CylBuff[i].BuffSema);
  1069.  
  1070.         CylBuff[i].Status = LEER;    // Buffer leer
  1071.  
  1072.         CylBuff[i].dbp = (BYTE *) AllocVec(globDrvDat.CylSize, globDrvDat.BufMemType);
  1073.         if (CylBuff[i].dbp == NULL)
  1074.             {
  1075.             char tLine[25];
  1076.  
  1077.             sprintf(tLine, "DiskBuffer %d", i);
  1078.             alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, tLine, globDrvDat.CylSize);
  1079.             myabort(10);
  1080.             }
  1081.         }
  1082.  
  1083.     ShowBuffStatus(&CylBuff[0], TRUE);    // Bufferstatus erstmalig anzeigen
  1084. }
  1085.  
  1086.  
  1087. void KMBytes(char *Line, unsigned long Value)
  1088. {
  1089.     unsigned long KBytes = Value / 1024l;
  1090.  
  1091.     if (Value > 2000*1024)
  1092.         {
  1093.         // alles > 2000 kB in MBytes anzeigen
  1094.         sprintf(Line, "%4ld%c%1d M", KBytes/1024l,
  1095.             GetDecimalPoint(),
  1096.             (10*KBytes/1024l) % 10);
  1097.         }
  1098.     else if (Value > 2048)
  1099.         {
  1100.         // alles > 2048 Bytes in KBytes anzeigen
  1101.         sprintf(Line, "%6ld K", KBytes);
  1102.         }
  1103.     else
  1104.         sprintf(Line, "%6ld ", Value);
  1105. }
  1106.  
  1107.  
  1108. static void DisplayNewDir(const struct DirEntry *aktdir)
  1109. {
  1110.     ASSERT_VALID(aktdir);
  1111.  
  1112.     if (aktdir->Done || *aktdir->Name == '\0')
  1113.         return;
  1114.  
  1115.     FDDisplayNewDir(AktPath);
  1116. }
  1117.  
  1118.  
  1119. void UpdateFileDisplay(void)
  1120. {
  1121.     static unsigned long LastFilesProcessed = ~0;
  1122.     static unsigned long LastBytesProcessed = ~0;
  1123.     char Text[80];
  1124.  
  1125.     if (FilesProcessed != LastFilesProcessed)
  1126.         {
  1127.         DisplayNewFile(Root_fib.fib_FileName);
  1128.         }
  1129.     if (BytesProcessed != LastBytesProcessed)
  1130.         {
  1131.         char BText1[20], BText2[20];
  1132.  
  1133.         KMBytes(BText1, BytesProcessed);
  1134.  
  1135.         if (myOptions.bo_Preview)
  1136.             {
  1137.             KMBytes(BText2, TotalBytes);
  1138.             sprintf(Text, GetString(MSG_BYTESPROCESSED_PREVIEW), BText1, BText2);
  1139.             }
  1140.         else
  1141.             sprintf(Text, GetString(MSG_BYTESPROCESSED), BText1, BText2);
  1142.  
  1143.         ShowByteCount(Text);
  1144.         }
  1145.  
  1146.     if (myOptions.bo_Preview)
  1147.         {
  1148.         if (BytesProcessed != LastBytesProcessed)
  1149.             ShowProgress(BytesProcessed, TotalBytes);
  1150.  
  1151.         sprintf(Text, GetString(MSG_FILESPROCESSED_PREVIEW),
  1152.             FilesProcessed, TotalFiles);
  1153.         }
  1154.     else
  1155.         {
  1156.         sprintf(Text, GetString(MSG_FILESPROCESSED), FilesProcessed);
  1157.         }
  1158.  
  1159.     if (FilesProcessed != LastFilesProcessed)
  1160.         ShowFileCount(Text);
  1161.  
  1162.     LastFilesProcessed = FilesProcessed;
  1163.     LastBytesProcessed = BytesProcessed;
  1164. }
  1165.  
  1166.  
  1167. void SetupNewDir(struct NextFileInfo *Info, const char *IncludePattern,
  1168.         struct DirEntry *aktdir)
  1169. {
  1170.     BPTR OldCurrentDir;
  1171.     int len;
  1172.     struct DirEntry *akt;
  1173.  
  1174.     ASSERT_VALID(Info);
  1175.     ASSERT_VALID(IncludePattern);
  1176.     ASSERT_VALID(aktdir);
  1177.  
  1178.     if (aktdir->Done)
  1179.         return;
  1180.  
  1181.     if (Info->nfi_DirLock)
  1182.         {
  1183.         UnLock(Info->nfi_DirLock);
  1184.         Info->nfi_DirLock = NULL;
  1185.         }
  1186.  
  1187.     if (AktPath != NULL)
  1188.         {
  1189.         free(AktPath);
  1190.         AktPath = NULL;
  1191.         }
  1192.     aktdir->Virgin = 0;
  1193.     aktdir->Contents = 0;
  1194.  
  1195.     len = strlen(IncludePattern) + 6;
  1196.     for (akt = aktdir; akt; akt = akt->Root)
  1197.         len += strlen(akt->Name) + 1;
  1198.     AktPath = (char *) calloc(len, 1);
  1199.     if (AktPath == NULL)
  1200.         {
  1201.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "AktPath", len);
  1202.         myabort(10);
  1203.         }
  1204.     *AktPath = '\0';
  1205.     for (akt = aktdir; akt; akt = akt->Root)
  1206.         {
  1207.         char c;
  1208.         int l;
  1209.  
  1210.         l = strlen(akt->Name);
  1211.         c = akt->Name[l-1];
  1212.         if (l > 0 && c != ':' && c != '/')
  1213.             strins(AktPath, "/");
  1214.         strins(AktPath, akt->Name);
  1215.         }
  1216.  
  1217.     // Der Abschluß von Pfaden mit '/' ist nicht notwendig und
  1218.     // führt bei SoftLinks sogar zu Problemen (Lock klappt nicht)
  1219.     len = strlen(AktPath);
  1220.     if (AktPath[len-1] == '/')
  1221.         AktPath[len-1] = '\0';
  1222.  
  1223.     Info->nfi_DirLock = Lock(AktPath, ACCESS_READ);
  1224.     if (Info->nfi_DirLock)
  1225.         {
  1226.         NameFromLock(Info->nfi_DirLock, NormalizedAktPath, sizeof(NormalizedAktPath));
  1227.  
  1228.         OldCurrentDir = CurrentDir(DupLock(Info->nfi_DirLock));
  1229.  
  1230.         if (InitialCurrentDir == ~0)
  1231.             InitialCurrentDir = OldCurrentDir;
  1232.         else
  1233.             UnLock(OldCurrentDir);
  1234.         }
  1235.     else
  1236.         {
  1237.         PostError(TRUE, MSGPRI_Warning, GetString(MSG_LOCK_FAILURE), __FUNC__,
  1238.             AktPath, GetIoErrText() );
  1239.         }
  1240.  
  1241.  
  1242.     if (AktPath[len-1] == '\0')
  1243.         AktPath[len-1] = '/';
  1244. }
  1245.  
  1246.  
  1247. struct DirEntry *NewDir(struct MinList *Home, const char *name, BOOL temp)
  1248. {
  1249.     size_t l;
  1250.     struct DirEntry *akt;
  1251.  
  1252.     ASSERT_VALID(Home);
  1253.     ASSERT_VALID(name);
  1254.  
  1255.     l = strlen(name);
  1256.  
  1257.     akt = (struct DirEntry *) malloc(sizeof(struct DirEntry) + l);
  1258.     if (akt == NULL)
  1259.         {
  1260.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "akt", sizeof(struct DirEntry) + l);
  1261.         myabort(10);
  1262.         }
  1263.  
  1264.     NewList((struct List *) &akt->Sub);
  1265.     akt->Root = NULL;
  1266.     akt->Virgin = 1;
  1267.     akt->Done = 0;
  1268.     akt->Temporary = temp;
  1269.     akt->Contents = 0;
  1270.     strcpy(akt->Name, name);
  1271.  
  1272.     AddTail((struct List *) Home, (struct Node *) akt);
  1273.  
  1274.     return akt;
  1275. }
  1276.  
  1277.  
  1278. // Prüfsumme für Buffer berechnen
  1279. unsigned long ComputeBufferCheckSum(const struct Buffer *buff)
  1280. {
  1281.     unsigned long CheckSum;
  1282.     const unsigned long *BuffPtr;
  1283.     size_t n;
  1284.  
  1285.     ASSERT_VALID(buff);
  1286.  
  1287.     for (CheckSum=0L, n=globDrvDat.CylSize/sizeof(long),
  1288.             BuffPtr=(const long *) buff->dbp;
  1289.             n; n--)
  1290.         {
  1291.         CheckSum += *BuffPtr++;
  1292.         }
  1293.  
  1294.     return CheckSum;
  1295. }
  1296.  
  1297.  
  1298. // Prüfsumme für DiskLabel berechnen
  1299. unsigned long ComputeLabelCheckSum(const struct DiskLabel *Label)
  1300. {
  1301.     unsigned long CheckSum;
  1302.     const unsigned long *LabelPtr;
  1303.     size_t n;
  1304.  
  1305.     ASSERT_VALID(Label);
  1306.  
  1307.     for (CheckSum=0L, n=sizeof(struct DiskLabel)/sizeof(long),
  1308.             LabelPtr=(const long *) Label;
  1309.             n; n--)
  1310.         {
  1311.         CheckSum += *LabelPtr++;
  1312.         }
  1313.  
  1314.     return CheckSum;
  1315. }
  1316.  
  1317.  
  1318. // Prüfsumme für FileLabel berechnen
  1319. unsigned long ComputeFileLabelCheckSum(const struct FileLabel *Label)
  1320. {
  1321.     unsigned long CheckSum;
  1322.     const unsigned long *LabelPtr;
  1323.     size_t n;
  1324.  
  1325.     ASSERT_VALID(Label);
  1326.  
  1327.     n = Label->FL_Length / sizeof(long);
  1328.     for (CheckSum=0L, LabelPtr=(const long *) Label; n; n--)
  1329.         {
  1330.         CheckSum += *LabelPtr++;
  1331.         }
  1332.  
  1333.     return CheckSum;
  1334. }
  1335.  
  1336.  
  1337. // Bestimmung der physikalischen Länge eines Files.
  1338. // Notwendig zum Lesen des Formats #0 (alt)
  1339. long FileLength(const struct DiskLabel *Label, const struct NameField *nf)
  1340. {
  1341.     long laenge;
  1342.  
  1343.     ASSERT_VALID(Label);
  1344.     ASSERT_VALID(nf);
  1345.  
  1346.     if (!nf->isComplete)
  1347.         {
  1348.         // File ist nicht vollständig auf dieser Disk
  1349.         laenge = Label->EndOfData - nf->Offset;
  1350.         if (COMPRESS_NONE == nf->CompressionType)
  1351.             laenge = min(laenge, nf->FileLen);
  1352.         }
  1353.     else
  1354.         {
  1355.         // File ist komplett
  1356.         if (nf->CompressionType != COMPRESS_NONE || nf->Extension)
  1357.             {
  1358.             if (nf->NextName)
  1359.                 {
  1360.                 // nicht das letzte File auf der Disk
  1361.                 laenge = nf->NextName->Offset - nf->Offset;
  1362.                 }
  1363.             else
  1364.                 {
  1365.                 // letztes File aus der Disk
  1366.                 laenge = Label->EndOfData - nf->Offset;
  1367.                 }
  1368.             }
  1369.         else
  1370.             {
  1371.             laenge = nf->FileLen;
  1372.             }
  1373.         }
  1374.     if (nf->FileLen == 0)
  1375.         laenge = 0;
  1376.  
  1377.     return (laenge);
  1378. }
  1379.  
  1380.  
  1381. void ShowBackupTime(void)
  1382. {
  1383.     static char zeile[80];
  1384.  
  1385.     sprintf(zeile, "%s %s %s %s",
  1386.         GetString(MSG_BACKUP_START),
  1387.         DateString(StartZeit[3], StartZeit[2], StartZeit[1]+1980),
  1388.         GetString(MSG_STARTTIME),
  1389.         TimeString(StartZeit[4], StartZeit[5], StartZeit[6]) );
  1390.     SessionInfo(zeile);
  1391. }
  1392.  
  1393.  
  1394. static ULONG __saveds __asm PreviewHookDisplay(register __a0 struct Hook *theHook,
  1395.         register __a1 object,
  1396.         register __a2 struct BCInfo *BCount)
  1397. {
  1398.     if (BCS_Final == BCount->bci_Status || 0 == BCount->bci_FileCount % BCount->bci_Threshold)
  1399.         {
  1400.         char Line[40];
  1401.  
  1402.         sprintf(Line, GetString(MSG_FILES_COLLECTED), BCount->bci_FileCount);
  1403.         ShowFileCount(Line);
  1404.         }
  1405.  
  1406.     return 0L;
  1407. }
  1408.  
  1409.  
  1410. static void action(void)
  1411. {
  1412.     if (!CheckPassword(&myOptions))    // ggf. Password anfordern
  1413.         return;
  1414.  
  1415.     getclk(StartZeit);            // Startzeit merken
  1416.  
  1417.     ShowBackupTime();            // Startzeit und -Datum anzeigen
  1418.  
  1419.     if (myOptions.bo_ProtFile != PT_None)
  1420.         OpenProtFile();
  1421.  
  1422.     NextFileAbort = FALSE;
  1423.     disknr = 0;
  1424.     DiskUnit = myOptions.bo_FirstUnit;
  1425.  
  1426.     if (!StartWriter())
  1427.         return;
  1428.  
  1429.     initDisk();                // Startet DiskChanger!
  1430.     InitBufReq();
  1431.  
  1432.     readoffset = globDrvDat.BlockSize;    // Sektor 0 überspringen, Header !
  1433.     AktPath = NULL;
  1434.  
  1435.     if (!InitSearchPattern(&myOptions))
  1436.         return;
  1437.  
  1438.     if (myOptions.bo_Preview)
  1439.         {
  1440.         // Files und Bytes zählen für Preview
  1441.         InfoLineHandle Pil;
  1442.         struct BCInfo BCount;
  1443.         struct Hook PreviewHook;
  1444.  
  1445.         PreviewHook.h_Entry = HookEntry;
  1446.         PreviewHook.h_SubEntry = (unsigned long (* )()) PreviewHookDisplay;
  1447.         PreviewHook.h_Data = NULL;
  1448.  
  1449.         Pil = PushInfoLine(GetString(MSG_CREATING_PREVIEW));
  1450.  
  1451.         DoByteCount(&myOptions, &BCount, &PreviewHook, 50);
  1452.  
  1453.         TotalBytes = BCount.bci_ByteCount;
  1454.         TotalFiles = BCount.bci_FileCount;
  1455.         NextFileAbort = FALSE;
  1456.  
  1457.         ShowFileCount("");
  1458.         PopInfoLine(&Pil);
  1459.         }
  1460.  
  1461.     NFInfo.nfi_TellSkips = TRUE;
  1462.  
  1463.     // Erste Disk anfordern.
  1464.     // Damit werden auch die endgültigen Werte in globDevInfo bestimmt.
  1465.     SignalNewDisk();
  1466.  
  1467.     // <maxbyte> anhand der engültigen globDevInfo-Daten nachtragen
  1468.     LockWriteDisk();
  1469.     WriteDisk.maxbyte = ReadDisk.maxbyte = globDrvDat.NumCyls * globDrvDat.CylSize;
  1470.     UnlockWriteDisk();
  1471.  
  1472.     // InitCompress() braucht die endgültigen globDevInfo-Daten !!!
  1473.     switch (myOptions.bo_Compress)
  1474.         {
  1475.     case COMPRESS_INTERNAL:
  1476.         if (!InitCompress())
  1477.             myOptions.bo_Compress = COMPRESS_NONE;
  1478.         break;
  1479.     case COMPRESS_XPK:
  1480.         if (!XPKInitCompress())
  1481.             myOptions.bo_Compress = COMPRESS_NONE;
  1482.         break;
  1483.         }
  1484.  
  1485.     CheckDriveFormat();
  1486.  
  1487.     AllocDiskBuffer();
  1488.  
  1489.     // Buffer erstmal zu 1/2 füllen
  1490.     while (!myOptions.bo_Append && !AllFilesRead && BuffersFull < BuffCount/2 )
  1491.         lesen();
  1492.  
  1493.     SignalBeginWriting();    // Jetzt mit Schreiben beginnen
  1494.  
  1495.     while (!AllFilesRead)
  1496.         lesen();
  1497.  
  1498.     if (!DB_EMPTY(ReadDisk))
  1499.         NewReadDisk(NULL);
  1500.  
  1501.     SignalDiskClose();        // "Letztes Medium komplett" an Writer-Prozeß melden
  1502.  
  1503.     CompressProtocol();        // jetzt ggf. Protokoll komprimieren
  1504.  
  1505.     while (!WriteReady())
  1506.         eingabe(0l);        // Warten bis alles geschrieben
  1507.  
  1508.     StopWriter(0);            // Writer-Prozeß beenden
  1509. }
  1510.  
  1511.  
  1512. // Prüft Filenamen zum komprimieren, offensichtlich bereits komprimierte
  1513. // Files werden nicht komprimiert.
  1514. // Ebenfalls nicht komprimiert werden Files, die kürzer als 100 Bytes sind
  1515. static void TestCompress(struct NameField *file)
  1516. {
  1517.     static const char *NCExt[] =
  1518.         { "Z", "ZOO", "ARC", "LZH", "ZIP", "LHA", NULL };
  1519.     char FileExt[FMSIZE];
  1520.     const char **akt;
  1521.  
  1522.     ASSERT_VALID(file);
  1523.  
  1524.     if (file->FileLen < 100l)
  1525.         return;
  1526.  
  1527.     switch (myOptions.bo_Compress)
  1528.         {
  1529.     case COMPRESS_NONE:
  1530.         return;
  1531.     case COMPRESS_XPK:
  1532.         break;        
  1533.     case COMPRESS_INTERNAL:
  1534.         stcgfe(FileExt, file->Name);
  1535.         for (akt=NCExt; *akt; akt++)
  1536.             {
  1537.             if (stricmp(FileExt, *akt) == 0)
  1538.                 return;
  1539.  
  1540.             if (*FileExt && MatchToolValue(myOptions.bo_NeverCompress, FileExt))
  1541.                 return;
  1542.             }
  1543.  
  1544.         // wegen der Rückwärts-Kompatibilität
  1545.         file->isCompressed = TRUE;
  1546.         break;
  1547.         }
  1548.  
  1549.     file->CompressionType = myOptions.bo_Compress;
  1550. }
  1551.  
  1552.  
  1553. enum BufferStatus GetBuffStatus(const struct Buffer *buff)
  1554. {
  1555.     ASSERT_VALID(buff);
  1556.  
  1557.     return buff->Status;
  1558. }
  1559.  
  1560.  
  1561. void SetBuffStatus(struct Buffer *buff, enum BufferStatus NewState)
  1562. {
  1563.     enum BufferStatus OldState;
  1564.  
  1565.     ASSERT_VALID(buff);
  1566.  
  1567.     ObtainSemaphore(&buff->BuffSema);
  1568.     OldState = buff->Status;
  1569.     buff->Status = NewState;
  1570.  
  1571.     if (NewState == VOLL && OldState != VOLL)
  1572.         BuffersFull++;
  1573.     else if (OldState == VOLL && NewState != VOLL)
  1574.         BuffersFull--;
  1575.  
  1576.     ASSERT_VALID(buff);
  1577.  
  1578.     ShowBuffStatus(&CylBuff[0], FALSE);    // Änderung gleich anzeigen
  1579.     ReleaseSemaphore(&buff->BuffSema);
  1580.  
  1581.     if (NewState == VOLL)
  1582.         SignalBufferFull();
  1583. }
  1584.  
  1585.  
  1586. void NextBuffNr(unsigned short *CurrentBuffNr)
  1587. {
  1588.     ASSERT_VALID(CurrentBuffNr);
  1589.  
  1590.     *CurrentBuffNr = (*CurrentBuffNr + 1) % BuffCount;
  1591. }
  1592.  
  1593.  
  1594. struct Buffer *GetBuffer(void)
  1595. {
  1596.     struct Buffer *aktbuff;
  1597.  
  1598.     aktbuff = &CylBuff[ReadBuffNr];
  1599.  
  1600.     switch (GetBuffStatus(aktbuff))
  1601.         {
  1602.     case VOLL:
  1603.         d(printf("aktbuff %2d %08lx: VOLL\n", ReadBuffNr, aktbuff));
  1604.         aktbuff = NULL;
  1605.         break;
  1606.     case FUELLEN:
  1607.         d(printf("aktbuff %2d %08lx: FUELLEN\n", ReadBuffNr, aktbuff));
  1608.         break;
  1609.     case LEER:
  1610.         d(printf("aktbuff %2d %08lx: LEER\n", ReadBuffNr, aktbuff));
  1611.         // Neuen Buffer suchen
  1612.         aktbuff->WritePtr = aktbuff->dbp + readoffset;
  1613.         aktbuff->disknr = ReadDisk.nr;        // Buffer zur aktuellen Disk-Nr. zuordnen
  1614.         aktbuff->BufferCheckSum = 0L;
  1615.         aktbuff->BuffFree = globDrvDat.CylSize - readoffset;
  1616.  
  1617.         if (ReadDisk.Offset == globDrvDat.BlockSize && readoffset == globDrvDat.BlockSize)
  1618.             {
  1619.             // Anfang einer neuen Disk, provisorisches Label anlegen
  1620.             BuildDiskLabel((struct DiskLabel *) aktbuff->dbp, ReadDisk.nr);
  1621.             }
  1622.  
  1623.         break;
  1624.     default:
  1625.         d(printf("aktbuff %2d %08lx: ???\n", ReadBuffNr, aktbuff));
  1626.         aktbuff = NULL;
  1627.         break;
  1628.         }
  1629.  
  1630.     AktReadBuffer = aktbuff;
  1631.  
  1632.     return aktbuff;
  1633. }
  1634.  
  1635.  
  1636. void BuildDiskLabel(struct DiskLabel *Label, short DiskNr)
  1637. {
  1638.     ASSERT_VALID(Label);
  1639.  
  1640.     memset(Label, 0, sizeof(struct DiskLabel));
  1641.  
  1642.     Label->LabelCheckSum = 0l;
  1643.     Label->DirCheckSum = 0l;
  1644.  
  1645.     Label->Version = Version;    // Versionsnummer
  1646.     Label->diskno = DiskNr;
  1647.     Label->RecordedFormat = BACKUP_FORMAT_ID;
  1648.     strcpy(Label->Id, DISKID);
  1649.     CopyMem(StartZeit, Label->BackupZeit, sizeof(StartZeit) );
  1650.  
  1651.     if (myOptions.bo_ProtFile != PT_None)
  1652.         {
  1653.         stccpy(Label->ProtFileName, myOptions.bo_ProtFileName,
  1654.             sizeof(Label->ProtFileName));
  1655.         }
  1656.  
  1657.     Label->LabelCheckSum = -ComputeLabelCheckSum(Label);
  1658. }
  1659.  
  1660.  
  1661. static unsigned long GetNewFile(struct Buffer *aktbuff, BOOL *FileFound)
  1662. {
  1663.     BPTR LinkLock;
  1664.     unsigned long filesize = 0;
  1665.     static BOOL filehanging = FALSE;    // zeigt an, wenn File mit NextFile() gefunden,
  1666.                     // aber auf ReadDisk kein Platz für den Dir.-
  1667.                     // Eintrag war.
  1668.  
  1669.     ASSERT_VALID(aktbuff);
  1670.     ASSERT_VALID(FileFound);
  1671.  
  1672.     if (!filehanging)
  1673.         {
  1674.         // Neues File suchen
  1675.         AllFilesRead = !NextFile(&NFInfo, &Root_fib);
  1676.  
  1677.         // ggf. nächste File-Spec. aus Kommandofile holen
  1678.         if (AllFilesRead && aktCmdFile)
  1679.             {
  1680.             char *path;
  1681.  
  1682.             path = ReadCmdFile(&myOptions, 1);
  1683.             if (path)
  1684.                 {
  1685.                 NewDir(&NFInfo.nfi_FirstDir, path, 0);
  1686.                 AllFilesRead = !NextFile(&NFInfo, &Root_fib);
  1687.                 }
  1688.             }
  1689.  
  1690.         // jetzt wirklich zu Ende, ProtFile wird ans Ende des Backups angehängt
  1691.         if (AllFilesRead && ProtFileHandle)
  1692.             {
  1693.             char ProtPath[FMSIZE];
  1694.  
  1695.             LockWriteDisk();
  1696.             if (!DB_EMPTY(WriteDisk) && !WriteDisk.dirwritten)
  1697.                 {
  1698.                 WriteProtFile(FIRST_NF(WriteDisk), WriteDisk.nr);
  1699.                 WriteDisk.dirwritten = TRUE;
  1700.                 }
  1701.             UnlockWriteDisk();
  1702.  
  1703.             if (!DB_EMPTY(ReadDisk) && !ReadDisk.dirwritten)
  1704.                 {
  1705.                 WriteProtFile(FIRST_NF(ReadDisk), ReadDisk.nr);
  1706.                 ReadDisk.dirwritten = TRUE;
  1707.                 }
  1708.  
  1709.             CleanupProtFile(TRUE);
  1710.  
  1711.             myOptions.bo_IncludeSubDirs = 0;
  1712.             myOptions.bo_UseArc = Ignore;
  1713.             myOptions.bo_SetArc = Set;
  1714.             myOptions.bo_UseFirstDate = 0;
  1715.             myOptions.bo_UseLastDate = 0;
  1716.  
  1717.             stcgfp(ProtPath, myOptions.bo_ProtFileName);
  1718.             NewDir(&NFInfo.nfi_FirstDir, ProtPath, 0);
  1719.  
  1720.             stccpy(myOptions.bo_IncludeFile.RawName, NurName(myOptions.bo_ProtFileName),
  1721.                 sizeof(myOptions.bo_IncludeFile.RawName) );
  1722.             myOptions.bo_IncludeFile.isParsed = 0;
  1723.             myOptions.bo_ExcludeFile.RawName[0] = '\0';
  1724.             myOptions.bo_ExcludeFile.isParsed = 0;
  1725.  
  1726.             InitSearchPattern(&myOptions);
  1727.  
  1728.             AllFilesRead = !NextFile(&NFInfo, &Root_fib);
  1729.             }
  1730.         }
  1731.  
  1732.     if (!AllFilesRead)
  1733.         {
  1734.         // Neues File gefunden
  1735.         if (EnterName(&Root_fib, ReadDisk.Offset, AktPath, NULL) != NULL)
  1736.             {
  1737.             filehanging = FALSE;
  1738.             *FileFound = TRUE;
  1739.  
  1740.             if (LONG_MIN == Root_fib.fib_DirEntryType)
  1741.                 {
  1742.                 // Partitions (Devices) behandeln
  1743.                 TestCompress(aktName);        // Partition kann komprimiert werden!
  1744.  
  1745.                 aktName->isPartition = 1;
  1746.                 aktName->FileLen = Root_fib.fib_Size = OpenPartition(aktName->Name, &Root_pInfo);
  1747.                 if (0 == aktName->FileLen)
  1748.                     {
  1749.                     PostError(TRUE, MSGPRI_Error, 
  1750.                             GetString(MSG_OPENPARTITION_FAILURE),
  1751.                             aktName->Name);
  1752.                     }
  1753.                 }
  1754.             else if (ST_USERDIR == Root_fib.fib_DirEntryType)
  1755.                 {
  1756.                 // Directories behandeln
  1757.                 aktName->isDir = 1;
  1758.                 aktName->isComplete = 1;
  1759.  
  1760.                 aktName->FileLen = Root_fib.fib_Size = 0;
  1761.                 }
  1762.             else if (!myOptions.bo_SaveSoftLinks &&
  1763.                     ST_SOFTLINK == Root_fib.fib_DirEntryType)
  1764.                 {
  1765.                 // SoftLinks behandeln (File oder Directory)
  1766.  
  1767.                 // Flag für SoftLink setzen, keine Kompression
  1768.                 aktName->isSoftLink = 1;
  1769.  
  1770.                 LinkPathPtr = LinkPath;
  1771.                 LinkLock = Lock(AktPath, ACCESS_READ);
  1772.  
  1773.                 if (LinkLock)
  1774.                     {
  1775.                     if (ReadLink(DeviceProc(AktPath), LinkLock,
  1776.                             Root_fib.fib_FileName, LinkPath,
  1777.                             sizeof(LinkPath)) )
  1778.                         {
  1779.                         aktName->FileLen = Root_fib.fib_Size = strlen(LinkPath) + 1;
  1780.                         }
  1781.                     else
  1782.                         {
  1783.                         PostError(TRUE, MSGPRI_Error,
  1784.                             GetString(MSG_READLINK_FAILURE),
  1785.                             ShortFileName(aktName->Name, 60),
  1786.                             GetIoErrText() );
  1787.                         }
  1788.  
  1789.                     UnLock(LinkLock);
  1790.                     }
  1791.                 else
  1792.                     {
  1793.                     PostError(TRUE, MSGPRI_Error,
  1794.                         GetString(MSG_LOCK_FAILURE), __FUNC__,
  1795.                         AktPath, GetIoErrText() );
  1796.                     }
  1797.                 }
  1798.             else if (!myOptions.bo_SaveHardLinks &&
  1799.                     (ST_LINKFILE == Root_fib.fib_DirEntryType ||
  1800.                      ST_LINKDIR == Root_fib.fib_DirEntryType) )
  1801.                 {
  1802.                 // HardLinks behandeln (File oder Directory)
  1803.  
  1804.                 // Flag für HardLink setzen, keine Kompression
  1805.                 aktName->isHardLink = 1;
  1806.  
  1807.                 LinkPathPtr = LinkPath;
  1808.                 LinkLock = Lock(aktName->Name, ACCESS_READ);
  1809.                 if (LinkLock)
  1810.                     {
  1811.                     if (NameFromLock(LinkLock, LinkPath, sizeof(LinkPath)))
  1812.                         {
  1813.                         aktName->FileLen = Root_fib.fib_Size = strlen(LinkPath) + 1;
  1814.                         }
  1815.                     else
  1816.                         {
  1817.                         PostError(TRUE, MSGPRI_Error, 
  1818.                             GetString(MSG_NAMEFROMLOCK_FAILURE),
  1819.                             ShortFileName(aktName->Name, 60),
  1820.                             GetIoErrText() );
  1821.                         }
  1822.                     UnLock(LinkLock);
  1823.                     }
  1824.                 else
  1825.                     {
  1826.                     PostError(TRUE, MSGPRI_Error, 
  1827.                         GetString(MSG_LOCK_FAILURE), __FUNC__,
  1828.                         ShortFileName(aktName->Name, 60), GetIoErrText() );
  1829.                     }
  1830.                 }
  1831.             else
  1832.                 {
  1833.                 // normale Files behandeln (keine Links)
  1834.                 TestCompress(aktName);
  1835.  
  1836.                 aktReadFileHandle = Open(Root_fib.fib_FileName, MODE_OLDFILE);
  1837.                 if (NULL == aktReadFileHandle)
  1838.                     {
  1839.                     PostError(TRUE, MSGPRI_Error,
  1840.                         GetString(MSG_CANNOT_OPENFILE),
  1841.                         ShortFileName(aktName->Name, 60),
  1842.                         GetIoErrText() );
  1843.  
  1844.                     *FileFound = FALSE;
  1845.                     }
  1846.                 }
  1847.  
  1848.             filesize = Root_fib.fib_Size;
  1849.             }
  1850.         else
  1851.             {
  1852.             // Kein Platz mehr auf ReadDisk für den Directory-Eintrag!
  1853.             // Der aktuelle Buffer wird mit 00 gefüllt und als VOLL deklariert.
  1854.             if (GetBuffStatus(aktbuff) == FUELLEN)
  1855.                 {
  1856.                 memset(AktReadBuffer->WritePtr, 0, AktReadBuffer->BuffFree);
  1857.                 BufferFull(aktbuff);
  1858.                 }
  1859.             filehanging = TRUE;
  1860.             NewReadDisk(&Root_fib);        // Weiterlesen für nächste Disk
  1861.             }
  1862.         }
  1863.     else
  1864.         {
  1865.         *FileFound = FALSE;
  1866.  
  1867.         // Backup fertig, "Buffer voll" melden.
  1868.         // Der aktuelle Buffer wird mit 00 gefüllt und als VOLL deklariert.
  1869.         if (GetBuffStatus(aktbuff) == FUELLEN)
  1870.             {
  1871.             memset(AktReadBuffer->WritePtr, 0, AktReadBuffer->BuffFree);
  1872.             BufferFull(aktbuff);
  1873.             }
  1874.  
  1875.         ClearFileName();    // Letzten Filenamen auf der Anzeige löschen
  1876.         }
  1877.  
  1878.     UpdateFileDisplay();
  1879.  
  1880.     return filesize;
  1881. }
  1882.  
  1883.  
  1884. // Der aktuelle Lese-Buffer in ReadDisk wird VOLL gemeldet.
  1885. // Liefert TRUE wenn neue ReadDisk, sonst FALSE
  1886. BOOL BufferFull(struct Buffer *aktbuff)
  1887. {
  1888.     BOOL NewDisk = FALSE;
  1889.  
  1890.     ASSERT_VALID(aktbuff);
  1891.  
  1892.     // aktueller Buffer ist voll
  1893.     SetBuffStatus(aktbuff, VOLL);
  1894.     aktbuff->BuffFree = 0l;
  1895.     readoffset = 0l;
  1896.     NextBuffNr(&ReadBuffNr);
  1897.  
  1898.     if (BuffersFull >= BuffCount/2 )
  1899.         SignalBeginWriting();    // Jetzt mit Schreiben beginnen
  1900.  
  1901.     // Es muß noch Platz sein für den neu anzulegenden Zylinder, sonst neue Disk
  1902.     if (isReadDiskFull(globDrvDat.CylSize))
  1903.         {
  1904.         // Disk ist voll
  1905.         NewReadDisk(&Root_fib);
  1906.         NewDisk = TRUE;
  1907.         }
  1908.  
  1909.     return NewDisk;
  1910. }
  1911.  
  1912.  
  1913. struct NameField *GetAktName(void)
  1914. {
  1915.     return aktName;
  1916. }
  1917.  
  1918.  
  1919. // Test, ob auf <ReadDisk> noch Platz ist für <ZusatzPlatz> Bytes.
  1920. // liefert TRUE wenn genug Platz, sonst FALSE.
  1921. static BOOL isReadDiskFull(unsigned long ZusatzPlatz)
  1922. {
  1923.     return (short) (ReadDisk.maxbyte < 
  1924.         ceildiv(ReadDisk.Offset, globDrvDat.CylSize) * globDrvDat.CylSize +
  1925.         ceildiv(ReadDisk.dirlength, globDrvDat.CylSize) * globDrvDat.CylSize +
  1926.         ZusatzPlatz);
  1927. }
  1928.  
  1929.  
  1930. static short lesen(void)
  1931. {
  1932.     static unsigned long filesize;
  1933.     static unsigned long FLSize;
  1934.     static BOOL FileInArbeit = FALSE;
  1935.     static BOOL inFileLabel = FALSE;
  1936.     static struct FileLabel *aktFileLabel = NULL;
  1937.     static struct FileLabel *FileLabelPtr;
  1938.     long NewFlags;
  1939.     short result;
  1940.  
  1941.     chkinput();
  1942.  
  1943.     if (AllFilesRead)            // Backup zu Ende
  1944.         return FALSE;
  1945.  
  1946.     GetBuffer();
  1947.  
  1948.     if (AktReadBuffer != NULL)    // freien Buffer gefunden
  1949.         {
  1950.         result = TRUE;
  1951.  
  1952.         if (!FileInArbeit)
  1953.             {
  1954.             filesize = GetNewFile(AktReadBuffer, &FileInArbeit);
  1955.  
  1956.             // FileLabel erzeugen wenn Backup auf Tape
  1957.             inFileLabel = AktReadBuffer->TapeReq != NULL;
  1958.             }
  1959.  
  1960.         if (FileInArbeit)
  1961.             {
  1962.             unsigned long readlen, count;
  1963.  
  1964.             if (GetBuffStatus(AktReadBuffer) == LEER)
  1965.                 {
  1966.                 // Neuen Buffer jetzt belegen
  1967.                 SetBuffStatus(AktReadBuffer, FUELLEN);
  1968.                 }
  1969.  
  1970.             if (inFileLabel)
  1971.                 {
  1972.                 // FileLabel sichern
  1973.                 if (aktFileLabel == NULL)
  1974.                     {
  1975.                     // aktFileLabel neu anlegen
  1976.                     long FLSkip;
  1977.  
  1978.                     // die Länge muß auf Langworte aufgerundet werden
  1979.                     FLSize = sizeof(struct FileLabel) + aktName->NameLen;
  1980.                     if (FLSize & 0x03)
  1981.                         FLSize = (FLSize & ~0x03) + 4;
  1982.  
  1983.                     aktFileLabel = calloc(FLSize, 1);
  1984.                     if (aktFileLabel == NULL)
  1985.                         {
  1986.                         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "aktFileLabel", FLSize);
  1987.                         myabort(10);
  1988.                         }
  1989.                     aktFileLabel->FL_Magic1 = FILELABEL;
  1990.                     aktFileLabel->FL_Magic2 = -FILELABEL;
  1991.                     aktFileLabel->FL_CheckSum = 0l;
  1992.                     aktFileLabel->FL_Length = FLSize;
  1993.  
  1994.                     CopyMem(aktName, &aktFileLabel->FL_nf, NF_LEN(aktName));
  1995.  
  1996.                     FileLabelPtr = aktFileLabel;
  1997.                     aktFileLabel->FL_nf.Offset += FLSize;
  1998.  
  1999.                     // Beginn des FileLabel an einer Block-Grenze
  2000.                     FLSkip = globDrvDat.BlockSize - (readoffset % globDrvDat.BlockSize);
  2001.                     if (FLSkip > 0 && FLSkip < globDrvDat.BlockSize)
  2002.                         {
  2003.                         memset(AktReadBuffer->WritePtr, 0, FLSkip);
  2004.                         readoffset += FLSkip;
  2005.                         ReadDisk.Offset += FLSkip;
  2006.                         AktReadBuffer->WritePtr += FLSkip;
  2007.                         AktReadBuffer->BuffFree -= FLSkip;
  2008.                         aktFileLabel->FL_nf.Offset += FLSkip;
  2009.                         }
  2010.  
  2011.                     aktFileLabel->FL_CheckSum = -ComputeFileLabelCheckSum(aktFileLabel);
  2012.                     }
  2013.  
  2014.                 readlen = min(FLSize, AktReadBuffer->BuffFree);
  2015.                 if (readlen)
  2016.                     CopyMem(aktFileLabel, AktReadBuffer->WritePtr, readlen);
  2017.  
  2018.                 FileLabelPtr += readlen;
  2019.                 FLSize -= readlen;
  2020.                 readoffset += readlen;
  2021.                 ReadDisk.Offset += readlen;
  2022.                 AktReadBuffer->WritePtr += readlen;
  2023.                 AktReadBuffer->BuffFree -= readlen;
  2024.  
  2025.                 if (FLSize == 0)
  2026.                     {
  2027.                     // FileLabel fertig gesichert
  2028.                     if (aktFileLabel)
  2029.                         free(aktFileLabel);
  2030.                     aktFileLabel = NULL;
  2031.                     inFileLabel = FALSE;
  2032.                     aktName->Offset = ReadDisk.Offset;
  2033.                     }
  2034.                 }
  2035.             else if (aktName->CompressionType != COMPRESS_NONE)
  2036.                 {
  2037.                 switch (aktName->CompressionType)
  2038.                     {
  2039.                 case COMPRESS_INTERNAL:
  2040.                     CompressFile(aktName, filesize, NULL);
  2041.                     break;
  2042.                 case COMPRESS_XPK:
  2043.                     XPKCompressFile(aktName, filesize);
  2044.                     break;
  2045.                 default:
  2046.                     alarm(GetString(MSG_UNKNOWNCOMPRESSION));
  2047.                     myabort(20);
  2048.                     break;
  2049.                     }
  2050.  
  2051.                 filesize = 0;
  2052.                 }
  2053.             else if (aktName->isSoftLink || aktName->isHardLink)
  2054.                 {
  2055.                 // Link sichern
  2056.                 readlen = min(filesize, AktReadBuffer->BuffFree);
  2057.                 if (readlen)
  2058.                     CopyMem(LinkPathPtr, AktReadBuffer->WritePtr, readlen);
  2059.  
  2060.                 LinkPathPtr += readlen;
  2061.                 filesize -= readlen;
  2062.                 readoffset += readlen;
  2063.                 ReadDisk.Offset += readlen;
  2064.                 AktReadBuffer->WritePtr += readlen;
  2065.                 AktReadBuffer->BuffFree -= readlen;
  2066.                 aktName->RecordedLen += readlen;
  2067.  
  2068.                 BytesProcessed += readlen;
  2069.                 }
  2070.             else if (aktName->isPartition)
  2071.                 {
  2072.                 // Partition sichern
  2073.                 readlen = min(filesize, AktReadBuffer->BuffFree);
  2074.                 ReadPartition(&Root_pInfo, readlen, AktReadBuffer->WritePtr);
  2075.  
  2076.                 filesize -= readlen;
  2077.                 readoffset += readlen;
  2078.                 ReadDisk.Offset += readlen;
  2079.                 AktReadBuffer->WritePtr += readlen;
  2080.                 AktReadBuffer->BuffFree -= readlen;
  2081.                 aktName->RecordedLen += readlen;
  2082.  
  2083.                 BytesProcessed += readlen;
  2084.                 }
  2085.             else if (aktName->isDir)
  2086.                 {
  2087.                 // Directory sichern
  2088.                 filesize = 0;
  2089.                 }
  2090.             else
  2091.                 {
  2092.                 // normales File sichern
  2093.                 readlen = min(filesize, AktReadBuffer->BuffFree);
  2094.  
  2095.                 if (aktReadFileHandle == NULL)
  2096.                     {
  2097.                     alarm("%s: aktReadFileHandle == NULL", __FUNC__);
  2098.                     myabort(30);
  2099.                     }
  2100.                 count = Read(aktReadFileHandle, AktReadBuffer->WritePtr, readlen);
  2101.  
  2102.                 if (count != readlen)
  2103.                     {
  2104.                     PostError(TRUE, MSGPRI_Error,
  2105.                         GetString(MSG_ERROR_READINGFILE),
  2106.                         ShortFileName(aktName->Name, 60),
  2107.                         GetIoErrText() );
  2108.                     filesize = count;
  2109.                     }
  2110.                 filesize -= count;
  2111.                 readoffset += count;
  2112.                 ReadDisk.Offset += count;
  2113.                 AktReadBuffer->WritePtr += count;
  2114.                 AktReadBuffer->BuffFree -= count;
  2115.                 aktName->RecordedLen += count;
  2116.                 BytesProcessed += readlen;
  2117.                 }
  2118.  
  2119.             if (0 == filesize)
  2120.                 {
  2121.                 // File fertig gelesen
  2122.                 aktName->isComplete = 1;        // File komplett auf akt. Disk
  2123.  
  2124.                 if (aktName->isPartition)
  2125.                     {
  2126.                     ClosePartition(&Root_pInfo);
  2127.                     }
  2128.                 if (LONG_MIN == Root_fib.fib_DirEntryType ||
  2129.                         Root_fib.fib_DirEntryType < 0)
  2130.                     {
  2131.                     // Achtung: genau gleiche Abfrage hier wie in GetByteCount()
  2132.                     FilesProcessed++;
  2133.                     }
  2134.  
  2135.                 if (aktReadFileHandle)
  2136.                     {
  2137.                     Close(aktReadFileHandle);
  2138.                     aktReadFileHandle = NULL;
  2139.                     }
  2140.  
  2141.                 aktNameDone();
  2142.                 FileInArbeit = FALSE;
  2143.  
  2144.                 // Jetzt Archiv-Flag setzen oder löschen
  2145.                 if (myOptions.bo_SetArc != Ignore && !aktName->isPartition)
  2146.                     {
  2147.                     NewFlags = Root_fib.fib_Protection;
  2148.  
  2149.                     switch (myOptions.bo_SetArc)
  2150.                         {
  2151.                     case Set:
  2152.                         NewFlags |= FIBF_ARCHIVE;
  2153.                         break;
  2154.                     case Reset:
  2155.                         NewFlags &= ~FIBF_ARCHIVE;
  2156.                         break;
  2157.                         }
  2158.  
  2159.                     if (NewFlags != Root_fib.fib_Protection &&
  2160.                         !SetProtection(Root_fib.fib_FileName, NewFlags))
  2161.                         {
  2162.                         if (!aktName->isDir)
  2163.                             {
  2164.                             PostError(TRUE, MSGPRI_Warning,
  2165.                                 GetString(MSG_ERROR_SETPROTECTION),
  2166.                                 ShortFileName(NurName(aktName->Name), 60),
  2167.                                 GetIoErrText() );
  2168.                             }
  2169.                         }
  2170.                     }
  2171.  
  2172.                 }
  2173.  
  2174.             if (AktReadBuffer && AktReadBuffer->BuffFree <= 0)
  2175.                 {
  2176.                 // aktueller Buffer ist voll
  2177.                 BufferFull(AktReadBuffer);
  2178.                 }
  2179.  
  2180.             UpdateFileDisplay();
  2181.             }
  2182.         }
  2183.     else    // alle Buffer sind voll
  2184.         {
  2185.         eingabe(0l);        // Warten bis Buffer leer oder Abbruch...
  2186.         result = FALSE;
  2187.         }
  2188.  
  2189.     return result;
  2190. }
  2191.  
  2192.  
  2193. static void initDisk(void)
  2194. {
  2195.     unsigned short i;
  2196.  
  2197.     assert(myOptions.bo_FirstUnit >= 0 && myOptions.bo_FirstUnit < NDisk);
  2198.  
  2199.     // globale Diskparameter provisorisch eintragen.
  2200.     // Die endgültigen Werte werden von newdisk() eingetragen sobald
  2201.     // die erste Disk eingelegt ist.
  2202.     globDrvDat = Disks[myOptions.bo_FirstUnit].DrvDat;
  2203.     globDrvDat.isPreliminary = TRUE;
  2204.  
  2205.     DiskChangeMaske = 0L;
  2206.  
  2207.     if (CylBuff[0].dbp)
  2208.         {
  2209.         for (i=0; i<BuffCount; i++)
  2210.             SetBuffStatus(&CylBuff[i], LEER);    // alle Buffer leer
  2211.         }
  2212.  
  2213.     InitSemaphore(&WriteDiskSema);
  2214.  
  2215.     NewList((struct List *) &ReadDisk.DirBuffers);
  2216.     ReadDisk.dirlength = 0;
  2217.     ReadDisk.diranf = 0;
  2218.     ReadDisk.diranz = 0;
  2219.     ReadDisk.maxbyte = globDrvDat.NumCyls * globDrvDat.CylSize;
  2220.     ReadDisk.Offset = globDrvDat.BlockSize;
  2221.     ReadDisk.nr = 1;
  2222.  
  2223.     LockWriteDisk();
  2224.     WriteDisk = ReadDisk;
  2225.     NewList((struct List *) &WriteDisk.DirBuffers);
  2226.     WriteDisk.dirwritten = 1;
  2227.     UnlockWriteDisk();
  2228.  
  2229.     AllFilesRead = FALSE;
  2230.     FilesProcessed = BytesProcessed = 0;
  2231.     aktName = NULL;
  2232.     ReadBuffNr = WriteBuffNr = OldestWriteBuffNr = 0;
  2233.  
  2234.     InitDiskUnit(myOptions.bo_FirstUnit, 1, TRUE);    // enthält StartDiskChanger()
  2235.  
  2236.     if (myOptions.bo_SecondUnit != NO_DRIVE)
  2237.         {
  2238.         InitDiskUnit(myOptions.bo_SecondUnit, 2, FALSE);
  2239.         DiskUnit = myOptions.bo_SecondUnit;        // nachher beginnen mit myOptions.bo_FirstUnit
  2240.         }
  2241.     else if (NULL == Disks[DiskUnit].TapeReq)
  2242.         GhostField();
  2243.  
  2244.     // feststellen ob Backup auf Tape
  2245.     toTape = Disks[DiskUnit].TapeReq != NULL;
  2246. }
  2247.  
  2248.  
  2249. static void InitDiskUnit(short Unit, short DiskNo, BOOL FirstDisk)
  2250. {
  2251.     assert(Unit >= 0 && Unit < NDisk);
  2252.  
  2253.     if (Disks[Unit].DcI)
  2254.         return;                // Unit ist schon initialisiert
  2255.  
  2256.     if (Disks[Unit].TapeReq == NULL)
  2257.         inhibit(TRUE, &Disks[Unit]);    // Laufwerk sperren
  2258.  
  2259.     Disks[Unit].DcI = StartDiskChanger(Unit, FirstDisk, DiskNo);
  2260.  
  2261.     if (Disks[Unit].DcI == NULL)
  2262.         {
  2263.         alarm(GetString(MSG_CANNOT_START_DISKCHANGER), Disks[Unit].DOSName);
  2264.         myabort(10);
  2265.         }
  2266. }
  2267.  
  2268.  
  2269. static void NewReadDisk(struct FileInfoBlock *fib)
  2270. {
  2271.     long save;
  2272.     short DiskNr;
  2273.  
  2274.     if (fib == NULL)
  2275.         {
  2276.         while (!DB_EMPTY(WriteDisk))
  2277.             Delay(25);        // 0.5s warten
  2278.         }
  2279.  
  2280.     LockWriteDisk();
  2281.     if (!DB_EMPTY(WriteDisk))
  2282.         {
  2283.         UnlockWriteDisk();
  2284.         alarm(GetString(MSG_INTERNALERROR_NEWREADDISK));
  2285.         myabort(50);
  2286.         }
  2287.  
  2288.     save = WriteDisk.Offset;
  2289.     WriteDisk = ReadDisk;
  2290.     WriteDisk.MaxOffset = ReadDisk.Offset;
  2291.     WriteDisk.Offset = save;
  2292.     DiskNr = WriteDisk.nr;
  2293.     MoveDirBuff(&WriteDisk, &ReadDisk);
  2294.     UnlockWriteDisk();
  2295.  
  2296.     ReadDisk.dirwritten = 0;
  2297.     ReadDisk.dirlength = 0;
  2298.     ReadDisk.diranf = 0;
  2299.     ReadDisk.diranz = 0;
  2300.     ReadDisk.maxbyte = globDrvDat.NumCyls * globDrvDat.CylSize;
  2301.     ReadDisk.nr = DiskNr + 1;
  2302.     ReadDisk.Offset = readoffset = globDrvDat.BlockSize;
  2303.  
  2304.     if (fib && aktName && !aktName->isComplete)
  2305.         {
  2306.         // Überlauf-Eintrag für letzte Datei behalten !
  2307.         struct NameField *Last;
  2308.  
  2309.         ASSERT_VALID(fib);
  2310.  
  2311.         aktNameDone();
  2312.  
  2313.         Last = aktName;
  2314.         aktName = NULL;
  2315.  
  2316.         EnterName(fib, ReadDisk.Offset, AktPath, Last);    // halbfertiges File auf der nächsten Disk weiterführen
  2317.         aktName->Extension++;
  2318.         aktName->RecordedLen = 0l;
  2319.         }
  2320.     else
  2321.         aktName = NULL;
  2322. }
  2323.  
  2324.  
  2325. void MoveDirBuff(struct Disk *Dest, struct Disk *Source)
  2326. {
  2327.     ASSERT_VALID(Dest);
  2328.     ASSERT_VALID(Source);
  2329.  
  2330.     NewList((struct List *) &(Dest->DirBuffers));
  2331.  
  2332.     // Alle Listeneinträge in DirBuffers umhängen von <Source> nach <Dest>
  2333.     while (!IsListEmpty((struct List *) &(Source->DirBuffers)))
  2334.         {
  2335.         struct Node *dbNode = (struct Node *) RemHead((struct List *) &Source->DirBuffers);
  2336.         AddTail((struct List *) &(Dest->DirBuffers), dbNode);
  2337.         }
  2338. }
  2339.  
  2340.  
  2341. // Verriegeln der NameField-Verkettung über <aktName>
  2342. void LockNFList(void)
  2343. {
  2344.     ObtainSemaphore(&NFSema);
  2345. }
  2346.  
  2347.  
  2348. // Entriegeln der NameField-Verkettung über <aktName>
  2349. void UnlockNFList(void)
  2350. {
  2351.     ReleaseSemaphore(&NFSema);
  2352. }
  2353.  
  2354.  
  2355. void FillNameField(struct NameField *akt, const struct FileInfoBlock *fib)
  2356. {
  2357.     akt->FileLen = fib->fib_Size;
  2358.     akt->FileDate = fib->fib_Date;
  2359.     akt->Protection = fib->fib_Protection;
  2360.     akt->NameLen = 0;
  2361.     akt->RecordedLen = 0l;
  2362.     akt->Extension = 0;
  2363.     akt->SessionNr = 0;
  2364.     akt->isComplete = 0;
  2365.     akt->isSoftLink = 0;
  2366.     akt->isHardLink = 0;
  2367.     akt->isDir = 0;
  2368.     akt->DiskNr = 0;
  2369.     akt->CompressionType = COMPRESS_NONE;
  2370.     akt->Reserved1 = 0;
  2371.     akt->Reserved2 = 0;
  2372.     akt->NFCheckSum = 0;
  2373. //    memset(akt->Reserved2, 0, sizeof(akt->Reserved2));
  2374. }
  2375.  
  2376.  
  2377. // ist ein Kommentar zum File (FileNote) vorhanden, wird er, getrennt
  2378. // durch ein \0, an den kompletten Filenamen angehängt.
  2379. // Return NULL, wenn der Platz auf der Diskette <ReadDisk> nicht mehr
  2380. // für den nächsten Directory-Buffer ausreicht.
  2381. struct NameField *EnterName(struct FileInfoBlock *fib, unsigned long offset,
  2382.     const char *path, struct NameField *Stencil)
  2383. {
  2384.     size_t pathlen, len;
  2385.     BOOL kommda;
  2386.     struct NameField *akt;
  2387.     char *commstr;
  2388.  
  2389.     LockNFList();
  2390.  
  2391.     if (Stencil)
  2392.         {
  2393.         ASSERT_VALID(Stencil);
  2394.         len = NF_LEN(Stencil);
  2395.         }
  2396.     else
  2397.         {
  2398.         ASSERT_VALID(path);
  2399.         ASSERT_VALID(fib);
  2400.  
  2401.         if (fib->fib_DirEntryType == ST_SOFTLINK)
  2402.             {
  2403.             // Softlinks jetzt auflösen
  2404.             static struct FileInfoBlock __aligned LinkFib;
  2405.             BPTR LinkLock;
  2406.  
  2407.             LinkLock = Lock((STRPTR) path, ACCESS_READ);
  2408.             if (LinkLock)
  2409.                 {
  2410.                 ResolveSoftLink(fib->fib_FileName, LinkLock, &LinkFib);
  2411.                 UnLock(LinkLock);
  2412.  
  2413.                 // wahre Filegröße eintragen
  2414.                 fib->fib_Size = LinkFib.fib_Size;
  2415.                 }
  2416.             else
  2417.                 {
  2418.                 PostError(TRUE, MSGPRI_Error,
  2419.                     GetString(MSG_LOCK_FAILURE), __FUNC__,
  2420.                     path, GetIoErrText() );
  2421.                 }
  2422.             }
  2423.  
  2424.         pathlen = strlen(path);
  2425.         kommda = (BOOL) (fib->fib_Comment[0]);        // Ist Kommentar (FileNote) vorhanden ?
  2426.         len = sizeof(struct NameField) + strlen(fib->fib_FileName) + pathlen;
  2427.         if (kommda)                    // Extra Platz für Kommentar reservieren
  2428.             len += strlen(fib->fib_Comment) + 1;
  2429.         }
  2430.  
  2431.     if (len & 0x01)
  2432.         len++;        // len auf gerade Werte runden
  2433. //    len = 2 * ceildiv(len, 2);    // len auf gerade Werte runden !
  2434.  
  2435.     if (DB_EMPTY(ReadDisk) || len > LATEST_DB(ReadDisk)->Space)
  2436.         {
  2437.         // neuen Buffer anlegen
  2438.         struct DirBlock *aktblock;
  2439.         unsigned long RestLaenge;
  2440.  
  2441.         // Es muß noch Platz sein für den neu anzulegenden Dir-Cylinder
  2442.         if (isReadDiskFull(globDrvDat.CylSize))
  2443.             {
  2444.             // kein Platz mehr auf ReadDisk
  2445.             UnlockNFList();
  2446.             return NULL;
  2447.             }
  2448.  
  2449.         RestLaenge = len - LATEST_DB(ReadDisk)->Space;
  2450.  
  2451.         aktblock = (struct DirBlock *) AllocVec( sizeof(struct DirBlock) + globDrvDat.CylSize, globDrvDat.BufMemType|MEMF_CLEAR);
  2452.         if (aktblock == NULL)
  2453.             {
  2454.             UnlockNFList();
  2455.             alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "aktblock", sizeof(struct DirBlock) + globDrvDat.CylSize);
  2456.             myabort(10);
  2457.             }
  2458.  
  2459.         aktblock->DataLength = aktblock->Space = globDrvDat.CylSize;
  2460.         aktblock->wp = aktblock->Data;
  2461.  
  2462.         if (RestLaenge < len)
  2463.             {
  2464.             akt = (struct NameField *) calloc(len, 1);
  2465.             if (akt == NULL)
  2466.                 {
  2467.                 UnlockNFList();
  2468.                 alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "akt", len);
  2469.                 myabort(10);
  2470.                 }
  2471.             aktblock->LostNF = akt;
  2472.  
  2473.             aktNameInfo.FirstPart = LATEST_DB(ReadDisk)->wp;
  2474.             aktNameInfo.SecondPart = aktblock->wp;
  2475.             aktNameInfo.FirstPartLen = LATEST_DB(ReadDisk)->Space;
  2476.             aktNameInfo.SecondPartLen = RestLaenge;
  2477.             aktNameInfo.aktName = akt;
  2478.             }
  2479.         else
  2480.             {
  2481.             aktblock->LostNF = NULL;
  2482.             akt = (struct NameField *) aktblock->wp;
  2483.             }
  2484.  
  2485.         LATEST_DB(ReadDisk)->Space = 0;
  2486.  
  2487.         AddTail((struct List *) &ReadDisk.DirBuffers, (struct Node *) aktblock);
  2488.  
  2489.         LATEST_DB(ReadDisk)->wp += RestLaenge;
  2490.         LATEST_DB(ReadDisk)->Space -= RestLaenge;
  2491.         }
  2492.     else
  2493.         {
  2494.         akt = (struct NameField *) LATEST_DB(ReadDisk)->wp;
  2495.         LATEST_DB(ReadDisk)->wp += len;
  2496.         LATEST_DB(ReadDisk)->Space -= len;
  2497.         }
  2498.  
  2499.     if (Stencil)
  2500.         {
  2501.         *akt = *Stencil;
  2502.         CopyMem(Stencil->Name, akt->Name, Stencil->NameLen+1);
  2503.         }
  2504.     else
  2505.         {
  2506.         FillNameField(akt, fib);
  2507.         akt->NameLen = strlen(fib->fib_FileName) + pathlen;
  2508.         if (kommda)
  2509.             akt->NameLen += strlen(fib->fib_Comment) + 1;
  2510.         akt->SessionNr = CurrentSessionNr;
  2511.  
  2512.         akt->DiskNr = ReadDisk.nr;
  2513.         akt->CompressionType = COMPRESS_NONE;
  2514.  
  2515.         strcpy(akt->Name, path);
  2516.         strcat(akt->Name, fib->fib_FileName);
  2517.     
  2518.         if (kommda)
  2519.             {
  2520.             // Kommentar zum File an den Namen anhängen
  2521.             commstr = akt->Name + strlen(akt->Name) + 1;
  2522.             strcpy(commstr, fib->fib_Comment);
  2523.             }
  2524.         }
  2525.  
  2526.     akt->Offset = offset;
  2527.  
  2528.     akt->NextName = NULL;
  2529.  
  2530.     if (aktName)
  2531.         aktName->NextName = akt;
  2532.  
  2533.     aktName = akt;
  2534.  
  2535.     ReadDisk.dirlength += len;
  2536.     ReadDisk.diranz++;
  2537.  
  2538.     UnlockNFList();
  2539.  
  2540.     return akt;
  2541. }
  2542.  
  2543.  
  2544. // liegt aktName auf der Grenze zwischen zwei DirBlocks, dann wird hier
  2545. // der endgültige Inhalt von aktName in die beiden DirBlocks kopiert.
  2546. // aktName selber wird nicht aufgelöst, da z.B. WriteProtFile() später noch
  2547. // über die Verkettung ->NextName darauf zugreift.
  2548. //
  2549. // Die hierfür temporär angelegten NameFields werden gelöscht in CleanupRWDisk().
  2550. void aktNameDone(void)
  2551. {
  2552.     ComputeNfChecksum(aktName);
  2553.  
  2554.     if (aktNameInfo.FirstPart && aktNameInfo.FirstPartLen)
  2555.         {
  2556.         CopyMem((char *) aktName, aktNameInfo.FirstPart, aktNameInfo.FirstPartLen);
  2557.         CopyMem(((char *) aktName) + aktNameInfo.FirstPartLen, aktNameInfo.SecondPart,
  2558.              aktNameInfo.SecondPartLen);
  2559.         aktNameInfo.FirstPart = NULL;
  2560.         aktNameInfo.FirstPartLen = 0;
  2561.         }
  2562. }
  2563.  
  2564.  
  2565. // sucht in ReadDisk nach dem File, das zwischen <MinOffset> und <MaxOffset>
  2566. // aufgezeichnet ist. Liefert den NameField zurück oder NULL
  2567. struct NameField *LookupFile(unsigned long MinOffset, unsigned long MaxOffset)
  2568. {
  2569.     struct NameField *akt;
  2570.     BOOL found = FALSE;
  2571.  
  2572.     akt = FIRST_NF(ReadDisk);
  2573.     while (akt && !found)
  2574.         {
  2575.         found = !((akt->Offset > MaxOffset) ||
  2576.               ((akt->Offset + akt->RecordedLen) < MinOffset));
  2577.  
  2578.         if (!found)
  2579.             akt = akt->NextName;
  2580.         }
  2581.  
  2582.     return akt;
  2583. }
  2584.  
  2585.  
  2586. // Laufwerk <Dsk>: sperren mit <onoff>=TRUE, mit <onoff>=FALSE => freigeben
  2587. static long inhibit(BOOL onoff, struct DiskFlags *Dsk)
  2588. {
  2589.     char tline[20];
  2590.     long erg;
  2591.  
  2592.     ASSERT_VALID(Dsk);
  2593.  
  2594.     Dsk->inhibited = onoff;
  2595.     sprintf(tline, "%s:", Dsk->DOSName);
  2596.     erg = Inhibit(tline, onoff ? DOSTRUE : DOSFALSE);
  2597.  
  2598.     // Spezialbehandlung:
  2599.     // wenn die Laufwerke DF0: bis DF3: benutzt werden,
  2600.     // wird (falls vorhanden) gleichzeitig PC0: bis PC3: stillgelegt,
  2601.     // da sich sonst der PCx-Handler mit Backup ins Gehege kommt.
  2602.     if (0 == strnicmp(Dsk->DOSName, "DF", 2) && strlen(Dsk->DOSName) == 3 && isdigit(Dsk->DOSName[2]))
  2603.         {
  2604.         short PCNr;
  2605.  
  2606.         PCNr = atoi(Dsk->DOSName + 2);
  2607.         if (PCNr >= 0 && PCNr <= 3)
  2608.             {
  2609.             char PCName[5];
  2610.  
  2611.             sprintf(PCName, "PC%d:", PCNr);
  2612.             Inhibit(PCName, onoff ? DOSTRUE : DOSFALSE);
  2613.             }
  2614.         }
  2615.  
  2616.     return erg;
  2617.         
  2618. }
  2619.  
  2620.  
  2621. // Prüfung, ob Ziel- und Quell-Device gleich sind.
  2622. // Return FALSE wenn Ok, TRUE wenn Quelle und Ziel sich überschneiden
  2623. static short CheckVolumes(const struct BackupOptions *Opt, short unit)
  2624. {
  2625.     static struct FileInfoBlock __aligned fib;
  2626.     long n;
  2627.     struct Process *Proc;
  2628.     APTR OrigWindowPtr;
  2629.     struct FSDir *Dir;
  2630.     BPTR VolLock;
  2631.     char VolumeName[FNSIZE+2];
  2632.  
  2633.     ASSERT_VALID(Opt);
  2634.  
  2635.     if (unit == NO_DRIVE)
  2636.         return FALSE;
  2637.  
  2638.     assert(unit >= 0 && unit < NDisk);
  2639.  
  2640.     if (Disks[unit].TapeReq)
  2641.         return FALSE;        // Tape kann keine Quelle sein
  2642.  
  2643.     Proc = (struct Process *) FindTask(NULL);
  2644.  
  2645.     OrigWindowPtr = Proc->pr_WindowPtr;
  2646.     Proc->pr_WindowPtr = (APTR) ~0;    // Fehler-Requester unterdrücken
  2647.  
  2648.     strcpy(VolumeName, Disks[unit].DOSName);
  2649.     strcat(VolumeName, ":");
  2650.     VolLock = Lock(VolumeName, ACCESS_READ);
  2651.  
  2652.     Proc->pr_WindowPtr = OrigWindowPtr;    // .. restaurieren
  2653.  
  2654.     if (VolLock)
  2655.         {
  2656.         Examine(VolLock, &fib);
  2657.         UnLock(VolLock);
  2658.         }
  2659.     else
  2660.         return FALSE;
  2661.  
  2662.     for (n=0; n<Opt->bo_FSDirCount; n++)
  2663.         {
  2664.         Dir = Opt->bo_FSDirList[n];
  2665.  
  2666.         if (Dir->fsd_SelectCount)
  2667.             {
  2668.             if (Dir->fsd_isVolList)
  2669.                 {
  2670.                 unsigned short cnt;
  2671.  
  2672.                 for (cnt=0; cnt<Dir->fsd_DirCount; cnt++)
  2673.                     {
  2674.                     if (Dir->fsd_EntryList[cnt]->fse_Selected && 
  2675.                         CmpVolumeName(Dir->fsd_EntryList[cnt]->fse_Name, fib.fib_FileName))
  2676.                         {
  2677.                         return TRUE;
  2678.                         }
  2679.                     }
  2680.                 }
  2681.             else if (CmpVolumeName(Dir->fsd_Name, fib.fib_FileName))
  2682.                 return 1;
  2683.             }
  2684.         }
  2685.  
  2686.     return FALSE;
  2687. }
  2688.  
  2689.  
  2690. static BOOL CmpVolumeName(char *DirName, char *VolName)
  2691. {
  2692.     BOOL Result;
  2693.     BPTR DirLock, VolLock;
  2694.  
  2695.     ASSERT_VALID(DirName);
  2696.     ASSERT_VALID(VolName);
  2697.  
  2698.     DirLock = Lock(DirName, ACCESS_READ);
  2699.     VolLock = Lock(VolName, ACCESS_READ);
  2700.  
  2701.     Result = SameDevice(DirLock, VolLock);
  2702.  
  2703.     if (DirLock)
  2704.         UnLock(DirLock);
  2705.     if (VolLock)
  2706.         UnLock(VolLock);
  2707.  
  2708.     return Result;
  2709. }
  2710.  
  2711.  
  2712. // Prüfen, ob die beiden eingestellten Laufwerke gleiche Formate haben
  2713. static void CheckDriveFormat(void)
  2714. {
  2715.     if (CheckVolumes(&myOptions, myOptions.bo_FirstUnit) || CheckVolumes(&myOptions, myOptions.bo_SecondUnit))
  2716.         {
  2717.         alarm(GetString(MSG_SAME_DEVICE));
  2718.         myabort(1);
  2719.         }
  2720. }
  2721.  
  2722.  
  2723. char *GetIoErrText(void)
  2724. {
  2725.     static char ErrBuff[80];
  2726.  
  2727.     ErrBuff[0] = '\0';
  2728.  
  2729.     Fault(IoErr(), (STRPTR) "", ErrBuff, sizeof(ErrBuff));
  2730.  
  2731.     return ErrBuff;
  2732. }
  2733.  
  2734.  
  2735. void LockWriteDisk(void)
  2736. {
  2737.     ObtainSemaphore(&WriteDiskSema);
  2738. }
  2739.  
  2740.  
  2741. void UnlockWriteDisk(void)
  2742. {
  2743.     ReleaseSemaphore(&WriteDiskSema);
  2744. }
  2745.  
  2746.  
  2747. // NameField-Prüfsumme berechnen
  2748. void ComputeNfChecksum(struct NameField *akt)
  2749. {
  2750.     char *p;
  2751.     size_t len;
  2752.     unsigned char Cks;
  2753.  
  2754.     ASSERT_VALID(akt);
  2755.  
  2756.     akt->NFCheckSum = 0;
  2757.     p = (char *) akt + sizeof(akt->NextName);
  2758.     for (len=sizeof(akt->NextName), Cks=0; len < NF_LEN(akt); len++)
  2759.         {
  2760.         Cks += *p++;
  2761.         }
  2762.     akt->NFCheckSum = -Cks;
  2763.  
  2764. //    if (!akt->isComplete)
  2765. //        {
  2766. //        kprintf(__FUNC__ ": Name=\"%s\" compl=%ld  Cks=%lx\n", akt->Name, (long) akt->isComplete, (long) akt->NFCheckSum);
  2767. //        }
  2768. }
  2769.  
  2770.  
  2771. #ifndef NDEBUG
  2772. extern void __assert(int, const char *, const char *, int);
  2773.  
  2774. void __assert(int Result, const char *Expression, const char *File, int Line)
  2775. {
  2776.     if (!Result)
  2777.         {
  2778.         alarm("File %s, Line %ld:\nAssertion \"%s\" Failed",
  2779.             File, Line, Expression);
  2780.         myabort(99);
  2781.         }
  2782. }
  2783. #endif
  2784.  
  2785.  
  2786. void main(int argc, char *argv[])
  2787. {
  2788.     long startzeit, endzeit;
  2789.     ULONG StackSize;
  2790.  
  2791.     OpenAll();
  2792.  
  2793.     StackSize = stacksize();
  2794.     if (StackSize < MIN_STACK - 512)
  2795.         {
  2796.         alarm(GetString(MSG_STACK_TOO_SMALL), MIN_STACK, StackSize);
  2797.         myabort(20);
  2798.         }
  2799.  
  2800.     GetParms(argc, argv);
  2801.  
  2802.     PrepareMainWindow(CmdFileName);
  2803.  
  2804.     if (NO_DRIVE != myOptions.bo_FirstUnit && Disks[myOptions.bo_FirstUnit].TapeReq)
  2805.         {
  2806.         Disks[myOptions.bo_FirstUnit].diskreq = OpenDisk(&Disks[myOptions.bo_FirstUnit], TRUE);
  2807.         if (Disks[myOptions.bo_FirstUnit].diskreq)
  2808.             {
  2809.             Disks[myOptions.bo_FirstUnit].TapeReq->Req = Disks[myOptions.bo_FirstUnit].diskreq;
  2810.  
  2811.             TapeInitProperties(Disks[myOptions.bo_FirstUnit].TapeReq);
  2812.             CloseDisk(&Disks[myOptions.bo_FirstUnit], CDP_KeepTape);
  2813.             CleanUpDisk(&Disks[myOptions.bo_FirstUnit], 0);
  2814.             }
  2815.  
  2816.         if (!Disks[myOptions.bo_FirstUnit].DrvDat.Properties.DriveKnown)
  2817.             {
  2818.             // Start mit einem unbekannten Bandlaufwerk
  2819.             alarm(GetString(MSG_UNKNOWN_TAPEDRIVE), Disks[myOptions.bo_FirstUnit].DOSName);
  2820.             SetupTape(aktWindow, &Disks[myOptions.bo_FirstUnit]);
  2821.  
  2822.             myabort(1);
  2823.             }
  2824.         }
  2825.  
  2826.     startzeit = gettime();
  2827.     action();
  2828.     endzeit = gettime();
  2829.  
  2830.     if (InteractiveBackup || ErrorCount)
  2831.         {
  2832.         SignalUnIconifyMainWindow();
  2833.         printstat(FilesProcessed, BytesProcessed, startzeit, endzeit, toTape);
  2834.         }
  2835. }
  2836.